问题描述
我有这个Oracle查询,大约需要1分钟才能得到结果:
SELECT TRUNC(sysdate - data_ricezione) AS delay
FROM notifiche@fe_engine2fe_gateway n
WHERE NVL(n.data_ricezione,TO_DATE('01011900','ddmmyyyy')) =
(SELECT NVL(MAX(n2.data_ricezione),'ddmmyyyy'))
FROM notifiche@fe_engine2fe_gateway n2
WHERE n.id_sdi = n2.id_sdi)
--AND sysdate-data_ricezione > 15
基本上,我有一个名为“ notifiche”的表,其中的每条记录代表一种对另一种对象(发票)的更新。我想知道过去15天内哪些发票未收到任何更新。我可以通过加入notifiche n2表,获取每张发票的最新记录并评估更新日期(data_ricezione)与当前日期(sysdate)之间的差异来做到这一点。
当我添加注释条件时,查询需要花费无限时间才能完成(我的意思是小时,从没见过结局...)
这种简单条件如何使查询如此缓慢?
如何提高性能?
解决方法
尝试保持data_ricezione
单独;如果上面有索引,可能会有所帮助。
所以:从以下位置切换
and sysdate - data_ricezione > 15
到
and -data_ricezione > 15 - sysdate / * (-1)
到
and data_ricezione < sysdate - 15
通过数据库链接完成所有操作后,请查看driving_site
提示是否有任何好处,即
select /*+ driving_site (n) */ --> "n" is table's alias
trunc(sysdate-data_ricezione) as delay
from
notifiche@fe_engine2fe_gateway n
...
,
使用解析函数来避免通过数据库链接进行自我联接。下面的查询仅从表中读取一次,将行划分为多个窗口,为每个窗口找到MAX
值,然后让您根据该最大值选择行。解析功能乍看之下很棘手,但通常会导致代码更小,更高效。
select id_sdi,data_ricezion
from
(
select id_sdi,data_ricezion,max(data_ricezion) over (partition by id_sdi) max_date
from notifiche@fe_engine2fe_gateway
)
where sysdate - max_date > 15;
关于为什么添加简单条件会使查询变慢的原因-全部与基数估计有关。基数(行数)决定着数据库优化程序的大多数决定。联接少量数据的最佳方法可能与联接大量数据的最佳方法大不相同。 Oracle必须始终猜测一个操作返回多少行,以知道要使用哪种算法。
优化器统计信息(有关表,列和索引的元数据)是Oracle用于进行基数估计的内容。例如,要猜测由sysdate-data_ricezione > 15
过滤出的行数,优化器将要知道表(DBA_TABLES.NUM_ROWS
)中有多少行,该列的最大值是({{ 1}}),也许可以细分不同年龄范围内的行数(DBA_TAB_COLUMNS.HIGH_VALUE
)。
所有这些信息取决于正确收集的优化器统计信息。如果DBA愚蠢地禁用了自动优化器统计信息收集,那么这些问题将一直存在。但是,即使您的系统使用了良好的设置,您使用的谓词也可能是特别困难的情况。优化器统计信息无法随意收集,因此系统仅在10%的数据更改时才收集统计信息。但是,由于您的谓词涉及DBA_TAB_HISTOGRAMS
,因此即使表未更改,行的百分比也会每天更改。可能比默认计划更频繁地手动收集此表上的统计信息,或使用SYSDATE
提示,或创建SQL Profile / Plan Baseline,或管理优化器统计信息和计划稳定性的多种方法之一。但是希望如果您使用分析函数而不是自联接,则不需要这些。