0

有没有一种方法可以通过避免多次计算某些重复值来提高此查询的性能,例如

regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM| TO |.csv|\d+:\d{2}:\d{2}', '')
? 和

to_date(regexp_replace(regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM|_TO_|\.csv|\d+:\d{2}:\d{2}', ''), '^(\d{4}- \d+-\d+)_.+$', '\1'), 'YYYY-MM-DD')

这些列计算了 3 次和 2 次,我运行了一些测试,仅通过删除 date_start 列,查询性能提高了大约 20 秒。我在想,如果 oracle 提供了一种更好的方法来保留值并避免多次计算,那就太好了。我也想避免

实际查询:

选择 *
从 (
  选择
      row_number() over(按 DCRAINTERNALNUMBER、ISSUE_DATE、PERMIT_ID 顺序按 to_date 分区(regexp_replace(regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM|_TO_|\.csv|\d+:\d{2}:\d{2}' , ''), '^.+_(\d{4}-\d+-\d+)_$', '\1'), 'YYYY-MM-DD') desc) 作为 row_order,
      to_date(regexp_replace(regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM|_TO_|\.csv|\d+:\d{2}:\d{2}', ''), '^(\d{4}- \d+-\d+)_.+$', '\1'), 'YYYY-MM-DD') 作为 date_start,
      to_date(regexp_replace(regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM|_TO_|\.csv|\d+:\d{2}:\d{2}', ''), '^.+_(\d{ 4}-\d+-\d+)_$', '\1'), 'YYYY-MM-DD') 作为 date_end,
      温度2.*
  来自 schema.TABLE_NAME temp2
) 吨

我还尝试模拟这样的事情以避免多次计算,但由于所有嵌套的选择语句,它并没有改善任何东西......它使查询变慢了大约 25 秒:

选择 *
从 (
  选择 row_number() over(按 DCRAINTERNALNUMBER、ISSUE_DATE、PERMIT_ID order by date_end desc 分区)作为 row_order,
  温度1.*
  从 (
      选择 to_date(regexp_replace(date_raw, '^(\d{4}-\d+-\d+)_.+$', '\1'), 'YYYY-MM-DD') 作为 date_start,
          to_date(regexp_replace(date_raw, '^.+_(\d{4}-\d+-\d+)_$', '\1'), 'YYYY-MM-DD') 作为 date_end,
      温度2.*
      从 (
      选择 regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM|_TO_|\.csv|\d+:\d{2}:\d{2}', '') 作为 date_raw,
        温度3.*
        来自 schema.TABLE_NAME temp3
      ) 温度 2

  ) 温度1
) 吨

4

3 回答 3

2

如果这是一个输入值很少的确定性 PL/SQL 函数,我当然会尝试更改:

select expensive_function(some_value)
from   large_table;

... 至 ...

select (select expensive_function(some_value) from dual)
from   large_table;

...因为 Oracle 有一个缓存机制。您可以尝试将 SQL 表达式推送到子查询中,如果这不起作用(或者即使它起作用),我会将该 SQL 代码移动到 PL/SQL 函数中并尝试它。

哦,如果您使用的是 11g,我当然会直接使用 pl/sql 函数缓存:http ://www.oracle.com/technetwork/issue-archive/2007/07-sep/o57asktom-101814.html

于 2013-05-13T13:09:37.157 回答
1

它没有回答您关于减少函数调用次数的具体问题,但您是否考虑过使用 regexp_substr 而不是多次调用 regexp_replace 函数?我认为这会做更少的工作,应该更快。如果数据不完全匹配(例如,如果文件名是 .txt 而不是 .csv),它也应该不太可能给你一个例外

就像是...

select * 
from (
  select row_number() over (partition by DCRAINTERNALNUMBER, ISSUE_DATE, PERMIT_ID order by to_date(regexp_substr(my_source_file,'\d{4}-\d{1,2}-\d{1,2}'),'yyyy-mm-dd') desc) as row_order,
  to_date(regexp_substr(my_source_file,'\d{4}-\d{1,2}-\d{1,2}'),'yyyy-mm-dd') as date_start,
  to_date(regexp_substr(my_source_file,'\d{4}-\d{1,2}-\d{1,2}',1,2),'yyyy-mm-dd') as date_end,
  temp2.* 
from schema.TABLE_NAME temp2) t

如果我正确解释了您的数据

TABLE_NAME_2011-3-1_11:00:00_AM_TO_2013-4-24_12:00:00_AM.csv

在此 2011-3-1 是开始日期,2013-4-24 是结束日期。我可以通过使用相同的模式匹配将它们放入一个日期,但选择开始日期的第一个实例(不需要参数,因为这是默认设置)和结束日期的第二个实例(这需要额外的 ,1,2 substr 从头开始​​(字符 1)并选择第二个实例。

希望有帮助。

于 2013-05-13T13:01:30.810 回答
0

不确定这会改善多少,但您可以使用 CTE:

with cte as (
  select tt.*, to_date(regexp_replace(regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM|_TO_|\.csv|\d+:\d{2}:\d{2}', ''), '^.+_(\d{4}-\d+-\d+)_$', '\1'), 'YYYY-MM-DD') calc_val
  from schema.TABLE_NAME tt
)
select * 
from (
  select
      row_number() over (partition by DCRAINTERNALNUMBER, ISSUE_DATE, PERMIT_ID order by calc_val desc) as row_order,
      calc_val as date_start,
      calc_val as date_end,
      temp2.* 
  from cte temp2
) t
于 2013-05-13T10:36:03.027 回答