有没有办法可以通过避免多次计算某些重复值来提高此查询的性能
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是否提供了更好的方法来保留值并避免多次计算会很棒。我也想避免
实际查询:
select * from ( select row_number() over (partition by DCRAINTERNALNUMBER, ISSUE_DATE, PERMIT_ID order by 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) as 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') as 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') as date_end, temp2.* from schema.TABLE_NAME temp2 ) t
我还尝试模拟这样的事情以避免多次计算,但是由于所有嵌套的select语句它没有改进任何东西......它使查询变慢约25秒:
select * from ( select row_number() over (partition by DCRAINTERNALNUMBER, ISSUE_DATE, PERMIT_ID order by date_end desc) as row_order, temp1.* from ( select to_date(regexp_replace(date_raw, '^(\d{4}-\d+-\d+)_.+$', '\1'), 'YYYY-MM-DD') as date_start, to_date(regexp_replace(date_raw, '^.+_(\d{4}-\d+-\d+)_$', '\1'), 'YYYY-MM-DD') as date_end, temp2.* from ( select regexp_replace(my_source_file, 'TABLE_NAME_|_AM|_PM|_TO_|\.csv|\d+:\d{2}:\d{2}', '') as date_raw, temp3.* from schema.TABLE_NAME temp3 ) temp2 ) temp1 ) t
答案 0 :(得分: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
答案 1 :(得分: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)并选择第二个实例。
希望有所帮助。
答案 2 :(得分: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