首页 > 解决方案 > 使用 EXISTS 指令是否改进了这个查询

问题描述

我正在学习如何改进我的一些查询,例如我看到使用 EXISTS 而不是 IN 效果更好,所以我做了以下修改,但我不能 100% 确定我是否能得到与使用 EXISTS 相同的结果,到目前为止它给出了当我在不同时期执行时,我得到了相同的结果,但我仍然怀疑,如果它确实存在更好的性能以及它是否做同样的事情,有人可以为我澄清吗?

VARIABLE periodo STRING;

SELECT MO.STRMOVANOMES,
C.STRCLINOMBRE,
MO.STRCLINIT,
MO.STROBLOBLIGSARC,
MO.NUMPROCODIGO,
MO.NUMMOVTIPOCREDITO,
MO.NUMMOVTIPOGARANTIA,
MO.STROBLMODALIDAD,
MO.NUMMOVCALIFICACION,
MO.NUMMOVVLRCAPCREDITO,
MO.NUMMOVVLRINTCREDI,
MO.NUMMOVVLRCAPOTRO
FROM TBLMOVOBLIGACIONES MO,
TBLCLIENTES C
WHERE MO.STRMOVANOMES = :periodo
AND C.STRCLITIPOID ='N' 
AND MO.NUMMOVTIPOCREDITO = 2
AND MO.NUMPROCODIGO IN (1,3,4,5,6,7,10,15,16,18,24,29,32,38,40,43,44,45,49,51,54,55,56,70,71,72,73,74,75,76,77,78,81,82,83,84,85)--ALL APPLICATIONS 
AND C.STRCLINIT=MO.STRCLINIT
AND SUBSTR(MO.STRCLINIT,1,9) >= 600000000  
AND SUBSTR(MO.STRCLINIT,1,9) <= 999999999;

 
-- USING EXISTS
SELECT MO.STRMOVANOMES,
C.STRCLINOMBRE,
MO.STRCLINIT,
MO.STROBLOBLIGSARC,
MO.NUMPROCODIGO,
MO.NUMMOVTIPOCREDITO,
MO.NUMMOVTIPOGARANTIA,
MO.STROBLMODALIDAD,
MO.NUMMOVCALIFICACION,
MO.NUMMOVVLRCAPCREDITO,
MO.NUMMOVVLRINTCREDI,
MO.NUMMOVVLRCAPOTRO
FROM TBLMOVOBLIGACIONES MO,
TBLCLIENTES C
WHERE MO.STRMOVANOMES = :periodo
AND C.STRCLITIPOID ='N' 
AND MO.NUMMOVTIPOCREDITO = 2
AND EXISTS (SELECT NUMPROCODIGO FROM TBLMOVOBLIGACIONES)--ALL APPLICATIONS 
AND C.STRCLINIT=MO.STRCLINIT
AND SUBSTR(MO.STRCLINIT,1,9) >= 600000000  
AND SUBSTR(MO.STRCLINIT,1,9) <= 999999999;

标签: sqloraclequery-performance

解决方案


首先,一些一般信息

理论上,当需要根据值列表检查某个值时,将使用 IN 子句,因此 DB 必须遍历列表以查找给定的值。而 EXIST 是让 db 执行快速查询(这是 db 设计的),以检查是否至少有一行。

如果您要检查的值列表在一个表中,通常最好使用 EXISTS。那是一些理论。

但在实践中,从版本 10(非常旧的版本)开始,Oracle 为 IN 和 EXISTS 查询构建了相同的执行计划,如果您需要一些更有经验的人,这里是一个很好的解释。

要检查它是否影响查询执行,请检查解释计划(google for it for your dev-tool)并比较总体“成本”(成本比较并不总是一件好事,但这种情况下没关系)

现在,回到您的查询。只要表 TBLMOVOBLIGACIONES 至少有一行,您使用它的方式中的 EXISTS 将始终返回 true。不确定这是您要找的东西。

我相信您需要以这种方式使用它

AND EXISTS (SELECT 1 FROM TBLMOVOBLIGACIONES WHERE NUMPROCODIGO = MO.NUMPROCODIGO)

因此它将检查是否至少有一条记录连接到您在上一步中选择的数据。

我在这里看到的下一步是 EXISTS 子句可以轻松转换为常规表连接,因此您可以编写以下内容,而不是在 IN 或 EXISTS 之间进行选择

 FROM TBLMOVOBLIGACIONES MO,
      TBLCLIENTES C,
      TBLMOVOBLIGACIONES M
WHERE MO.STRMOVANOMES = :periodo
AND C.STRCLITIPOID ='N' 
AND MO.NUMMOVTIPOCREDITO = 2
AND M.NUMPROCODIGO = MO.NUMPROCODIGO--ALL APPLICATIONS 
AND C.STRCLINIT=MO.STRCLINIT
AND SUBSTR(MO.STRCLINIT,1,9) >= 600000000  
AND SUBSTR(MO.STRCLINIT,1,9) <= 999999999;

这是值得做的,因为连接总是更好的选择,允许数据库改变表连接顺序以获得更好的性能。


推荐阅读