[英]How to optimize performance of this SQL query
我需要找到每一天的年龄,但是我需要在一个查询中找到所有以前的日期。 因此,我使用了以下查询:
select trunc(sysdate) - level + 1 **DATE**
,trunc(sysdate) - level + 1 - created_date **AGE** from items
connect by trunc(sysdate) - level + 1 - created_date > 0
我得到的输出(日期和年龄)正确无误:
DATE AGE
--------- ----------
6-JUL-15 22
5-JUL-15 21
4-JUL-15 20
3-JUL-15 19
2-JUL-15 18
1-JUL-15 17
30-JUN-15 16
29-JUN-15 15
28-JUN-15 14
27-JUN-15 13
26-JUN-15 12
25-JUN-15 11
24-JUN-15 10
现在,我需要计算每天的平均年龄 ,因此在以下查询中添加了平均年龄 :
select trunc(sysdate) - level + 1 **DATE** ,
**avg**(trunc(sysdate) - level + 1 - created_date )** AVERAGE_AGE**
from items
connect by trunc(sysdate) - level + 1 - created_date > 0
group by trunc(sysdate) - level + 1
这个查询正确吗? 当我向该查询添加聚合函数(avg)时,它需要1个小时来检索数据。 当我从查询中删除平均值函数时,它会在2秒内给出结果吗? 在不影响性能的情况下计算平均值的可能解决方案是什么?
抱歉,我从未使用过Oracle,因此即使我尝试阅读doc以获得语法详细信息,也可能会出现一些错误:
您说此查询在2秒内完成了工作:
select trunc(sysdate) - level + 1 **DATE**
,trunc(sysdate) - level + 1 - created_date **AGE** from items
connect by trunc(sysdate) - level + 1 - created_date > 0
因此,我们将保留它并从中进行view
:
CREATE OR REPLACE VIEW my_view AS
(select
trunc(sysdate) - level + 1 **DATE** AS "date_col",
trunc(sysdate) - level + 1 - created_date **AGE** AS "age_col"
from items
connect by trunc(sysdate) - level + 1 - created_date > 0);
但是通过执行以下操作,可能我们可以获得一些多余的计算:
CREATE OR REPLACE VIEW distinct_dates AS
(
SELECT DISTINCT trunc(sysdate) - level + 1 AS "date_distinct"
from items
connect by trunc(sysdate) - level + 1 - created_date > 0
);
CREATE OR REPLACE VIEW my_view AS
(select
date_distinct AS "date_col",
date_distinct - created_date AS "age_col"
from distinct_dates
connect by date_distinct - created_date > 0);
我为什么要这么做? 因为看来问题出在聚合上,所以恐怕视图实际上是在您的代码中多次计算的。 下一步只是在视图上进行计算:
select
date_col ,
AVG(age_col)
from my_view
group by date_col;
最后,最终代码将是:
CREATE OR REPLACE VIEW distinct_dates AS
(
SELECT DISTINCT trunc(sysdate) - level + 1 AS "date_distinct"
from items
connect by trunc(sysdate) - level + 1 - created_date > 0
);
CREATE OR REPLACE VIEW my_view AS
(select
date_distinct AS "date_col",
date_distinct - created_date AS "age_col"
from distinct_dates
connect by date_distinct - created_date > 0);
select
date_col ,
AVG(age_col)
from my_view
group by date_col;
或者,如果它不起作用:
CREATE OR REPLACE VIEW my_view AS
(select
trunc(sysdate) - level + 1 **DATE** AS "date_col",
trunc(sysdate) - level + 1 - created_date **AGE** AS "age_col"
from items
connect by trunc(sysdate) - level + 1 - created_date > 0);
select
date_col ,
AVG(age_col)
from my_view
group by date_col;
修改后的查询:
select tdate, avg(trunc(tdate)-created_date) AVG_AGE
from (
select trunc(sysdate) - level + 1 tdate
from (select min(created_date) dt from items)
connect by trunc(sysdate) - level + 1 - dt > 0 ) dates
join items on dates.tdate > items.created_date
group by tdate order by tdate
假设您只有两行,日期分别为“ 2015-06-01”和“ 2015-06-20”。 根据我的计算,您的层次查询为它们生成了1376254行,这可能不是您想要的,它应该生成51行(35 + 16)。 这就是为什么要花这么长时间的原因,因为表items
更多行输出呈指数增长。
您可以通过添加某种计数器(由rownum
或row_number
生成),然后添加and prior rn = rn
connect by
子句来修改查询,但是上面显示的查询使查询更简单。 我在SQLFiddle中添加了第二个查询以比较结果,两者均产生相同的输出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.