【发布时间】: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/…
标签: sql oracle hibernate query-performance