Oracle“优化” OR + IN 到 OR + EXISTS,这非常慢
Posted
技术标签:
【中文标题】Oracle“优化” OR + IN 到 OR + EXISTS,这非常慢【英文标题】:Oracle "optimizes" OR + IN to OR + EXISTS which is very slow 【发布时间】:2018-04-06 05:23:55 【问题描述】:我有以下疑问:
select * from application_log log
where log.tag_value = 'xxx'
or log.tag_value in (select transaction.id
from transaction transaction where transaction.sale_id = 'xxx')
order by log.log_date asc;
并根据解释计划将子查询转换为类似的内容:
EXISTS (SELECT 0 FROM TRANSACTION TRANSACTION
WHERE TRANSACTION.SALE_ID='xxx' AND TRANSACTION.ID=:B1)
所以IN
被替换为EXISTS
并且子查询不会执行一次,而是针对 application_log 表中的每条记录执行,如果 application_log 表中有超过一百万条记录,这将非常慢。
我可以用UNION
替换OR
,这非常快,但由于Hibernate (JPA) 不支持UNION
,这对我来说不是解决方案。
select * from application_log log
where
log.tag_value in (select 'xxx' from dual union select transaction.id
from transaction transaction where transaction.sale_id = 'xxx')
order by log.log_date asc;
那么是否有一些 Oracle 提示告诉 Oracle 不要使用 EXISTS
或其他方式来“优化”查询,我该如何重写这个查询?
【问题讨论】:
如果 Oracle 进行这种转换,那是因为它认为这将是获取结果的最有效方式。您是否检查过您的数据库统计信息是否正常?你的表名让我觉得它们的大小并不稳定,而且还在不断增加。因此,如果您希望 Oracle 做出正确的决定,您必须确保统计数据是相当最新的。 发布执行计划 @ibre5041在 Oracle 中打印一些文本版本的执行计划的最佳方法是什么?我正在使用 Oracle SQL Developer,它只在 UI 中直观地显示。 @gpeche 我不知道应该如何检查统计数据是否正常。是的,桌子的大小一直在增长。 @martinsefcik 首先,您应该检查ALL_TAB_COLS
和ALL_TAB_COL_STATISTICS
中为您的APPLICATION_LOG
和TRANSACTION
表注册的统计信息是否与这些表中的实际数据匹配。 Oracle 优化器使用该信息来猜测最佳查询执行计划是什么,因此如果信息不正确/过时,则执行计划将不是最佳的。理想情况下,您的 DBA 可以检查统计数据并在必要时更新它们。见:docs.oracle.com/cd/E18283_01/server.112/e17110/…docs.oracle.com/cd/E18283_01/server.112/e17110/…
【参考方案1】:
您可以将子查询转换为连接:
SELECT *
FROM application_log log
LEFT JOIN transaction transaction ON log.tag_value=transaction.id AND transaction.sale_id = 'xxx'
WHERE log.tag_value = 'xxx' OR transaction.id IS NOT NULL
ORDER BY log.log_date ASC;
【讨论】:
它比使用OR
+ IN
(24 秒)的查询快大约 3 倍(8 秒),但与使用 UNION
的查询(0.1 秒)相比仍然太慢。
以上是关于Oracle“优化” OR + IN 到 OR + EXISTS,这非常慢的主要内容,如果未能解决你的问题,请参考以下文章