如何优化此SQL查询

时间:2016-06-29 10:14:17

标签: sql oracle

此查询占用的时间超过4 minutes,我想让它运行得更快。请提供任何建议

SELECT *
FROM fact_acct zz
WHERE zz.C_AcctSchema_ID=1000000
AND zz.PostingType      ='A'
AND TRUNC(zz.DateAcct,'DD') BETWEEN TO_DATE('2016-01-01','YYYY-MM-DD') AND TO_DATE('2016-01-01','YYYY-MM-DD')
AND Z_Id_Cpt_To_Val(Account_ID) <= Z_Id_Cpt_To_Val(1001508)
AND Z_Id_Cpt_To_Val(Account_ID) >= Z_Id_Cpt_To_Val(1001508) 

函数Z_Id_Cpt_To_Val ()是问题的原因,它在这个SQL中运行所有查询,所以需要很长时间

因为如果我退出最后两行,这个sql会在3 secondes中给出结果

所以,任何想要优化的想法

谢谢

3 个答案:

答案 0 :(得分:1)

如果没有plan和ddl,那将只是假设。

第一个假设

你有关于fact_acct.DateAcct,TRUNC(fact_acct.DateAcct,'DD')的索引 - 不会使用索引 TRUNC(fact_acct.DateAcct,'DD')仅修剪小时/分钟/秒部分。 你可以使用

zz.DateAcct >= BETWEEN TO_DATE('2016-01-01','YYYY-MM-DD') <TO_DATE('2016-01-02','YYYY-MM-DD')

第二个假设

而不是

Z_Id_Cpt_To_Val(Account_ID) <= Z_Id_Cpt_To_Val(1001508)

 (select Z_Id_Cpt_To_Val(Account_ID) from dual) <= (select Z_Id_Cpt_To_Val(1001508) from dual)

每次使用缓存机制时,Oracle都不会执行此功能。但要小心!如果您希望Oracle始终执行Z_Id_Cpt_To_Val,那么您不需要这种方法

答案 1 :(得分:0)

如果问题出现在过多的函数调用中,并且您使用的是最新版本的Oracle(11g中的东西),您可以从subquery caching中获利。

简单地重写对子查询的所有函数调用:

select *  from t1
where (select Z_Id_Cpt_To_Val(Account_ID) from dual) between ...

如果您有大量记录和一些ACCOUNT_ID或订购了ACCOUNT_ID,这将有效。

答案 2 :(得分:0)

我想知道使用这样的CTE是否会有所帮助:

WITH zz as (
      SELECT *
      FROM fact_acct zz
      WHERE zz.C_AcctSchema_ID = 1000000 AND
            zz.PostingType = 'A' AND AND
            zz.DateAcct >= TO_DATE('2016-01-01', 'YYYY-MM-DD') AND
            zz.DateAcct < TO_DATE('2016-01-02', 'YYYY-MM-DD')
     )
SELECT zz.*
FROM zz CROSS JOIN
     (SELECT Z_Id_Cpt_To_Val(1001508) as cv FROM dual) x
WHERE Z_Id_Cpt_To_Val(Account_ID) = x.cv;

对于CTE,您需要fact_acct(C_AcctSchema_ID, PostingType, DateAcct)上的索引。

注意:关于函数的WHERE子句中的条件可以简化为=,假设函数为给定的参数集返回相同的值。

如果这没有帮助,您将需要深入了解该功能本身。