sql - 使用 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;
解决方案
首先,一些一般信息
理论上,当需要根据值列表检查某个值时,将使用 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;
这是值得做的,因为连接总是更好的选择,允许数据库改变表连接顺序以获得更好的性能。
推荐阅读
- apache-spark - 使用 Notebook 将 Azure Synapse 数据库中的数据加载到 DataFrame
- json - 从响应中提取损坏的 JSON
- javascript - Discord.js V12:如何移动类别?
- unity3d - 使物体与检测到的 AR 平面平行(适合)
- c++ - 最大传输速度 ESP8266?
- linux - 在系统级别修改 http 标头
- flutter - Flutter pub 失败(服务器不可用)-客户端中的 Hanshake 错误
- python - 在 Django admin 中创建对象时会发生什么?
- android - 创建了虚拟键盘,但即使在虚拟键盘设置中选择新键盘后也会出现默认键盘
- .net - Firefox:301 重定向在私人窗口中工作,导致常规窗口超时