【问题标题】:Oracle "optimizes" OR + IN to OR + EXISTS which is very slowOracle“优化” OR + IN 到 OR + EXISTS,这非常慢
【发布时间】: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_COLSALL_TAB_COL_STATISTICS 中为您的APPLICATION_LOGTRANSACTION 表注册的统计信息是否与这些表中的实际数据匹配。 Oracle 优化器使用该信息来猜测最佳查询执行计划是什么,因此如果信息不正确/过时,则执行计划将不是最佳的。理想情况下,您的 DBA 可以检查统计数据并在必要时更新它们。见:docs.oracle.com/cd/E18283_01/server.112/e17110/…docs.oracle.com/cd/E18283_01/server.112/e17110/…

标签: sql oracle hibernate query-performance


【解决方案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 秒)相比仍然太慢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-29
  • 1970-01-01
  • 1970-01-01
  • 2015-06-05
  • 2016-09-22
相关资源
最近更新 更多