与硬编码值相比,Oracle SQL In Subquery 花费了太多时间

Posted

技术标签:

【中文标题】与硬编码值相比,Oracle SQL In Subquery 花费了太多时间【英文标题】:Oracle SQL In Subquery taking too much time as compared to hard coded values 【发布时间】:2019-06-21 11:55:50 【问题描述】:

我有一个简单的查询,运行大约需要 2 分钟,而使用硬编码值执行时需要 8 秒。

SELECT * 
FROM TABLE_A
WHERE TRANSACTION_DATE = (SELECT PREV_WORKING_DAY 
                          FROM TABLE_B )

SELECT PREV_WORKING_DAY FROM TABLE_B 返回 '20-JUN-2019'。

TRANSACTION_DATE 和 PREV_WORKING_DAY 都是日期格式。

当我们在查询输出中硬编码日期为 100 毫秒时

SELECT * 
FROM TABLE_A
WHERE TRANSACTION_DATE = '20-JUN-2019'

总记录 = 82,000

知道是什么导致了使用子查询时的延迟,以及我们如何对其进行优化。

我知道我可以在 PL/SQL 中转换相同的值并将值分配给一个变量,但我仍然想了解导致延迟的原因。 谢谢

【问题讨论】:

表 B 有一行?还是您未显示的两个表之间存在某种相关性? (另外,'20-JUN-2019' 不是日期,它是一个字符串,因此正在进行隐式转换)。您可能希望包含两个查询的执行计划。 您有超过 TABLE_A 的索引吗?解释两个查询,看看第一个查询是否没有使用索引。 'SELECT PREV_WORKING_DAY FROM TABLE_B' 如何只返回一行?表格中只有一行吗? 是的,table_B 只有一条 PREV_WORKING_DAY 记录。 @AlexPoole Table_A 和 Table_B 之间的唯一关系是 TRANSACTION_DATE。基本上,Table_A 保留了我所有交易的列表,Table_B 保留了 My Previous_working_day、今天和下一个工作日的记录。 【参考方案1】:

我的猜测是您没有或非常陈旧的 TABLE_B 统计信息,因此 Oracle 不知道它只有一行。因此,它选择了一个低效的计划。 解释计划将告诉您子查询的基数。

如果是这样,解决方案是:

dbms_stats.gather_table_stats(user, 'TABLE_B');

您应该阅读the documentation on gathering statistics。

【讨论】:

【参考方案2】:

如果您切换到JOIN,会发生什么?

SELECT A.*
FROM TABLE_A A JOIN
     TABLE_B B
     ON A.TRANSACTION_DATE B.PREV_WORKING_DAY;

【讨论】:

能否提供两个查询的执行计划

以上是关于与硬编码值相比,Oracle SQL In Subquery 花费了太多时间的主要内容,如果未能解决你的问题,请参考以下文章

与硬编码输入相比,使用 fgets 从用户获取密钥时无法打印密钥流

Oracle In(匹配)子句

Oracle In(匹配)子句

XML 与硬编码接口?

如何按 Oracle SQL IN() 子句中的值顺序对结果数据进行排序

java调用oracle存储过程 关于sql里面in函数参数的问题