首页 > 技术文章 > exists改写SQL,使其走正确的执行计划

boss-he 2015-08-27 20:07 原文

数据库环境:SQL SERVER 2005

  今天看到一条SQL,写得不是很复杂,返回7000多条数据,却执行了15s。SQL文本及各表的数据量如下:

SELECT  acinv_07.id_item ,
        SUM(acinv_07.dec_endqty) dec_endqty
FROM    acinv_07
WHERE   acinv_07.fiscal_year * 100 + acinv_07.fiscal_period = ( SELECT DISTINCT
                                                              ctlm1101.fiscal_year
                                                              * 100
                                                              + ctlm1101.fiscal_period
                                                              FROM
                                                              ctlm1101
                                                              WHERE
                                                              flag_curr = 'Y'
                                                              AND id_oprcode = 'acinv'
                                                              AND acinv_07.id_wh = ctlm1101.id_table
                                                              )
GROUP BY acinv_07.id_item
----------------------------------------
SELECT  COUNT(*)
FROM    ctlm1101
WHERE   flag_curr = 'Y'
        AND id_oprcode = 'acinv'--26
        
SELECT  COUNT(*)
FROM    acinv_07--1347176
View Code

  我们先看看一下SQL的执行计划

  2个表关联走的是嵌套循环,且大表acinv_07是驱动表,ctlm1101被扫描了1347176次,

ctlm1101.id_table是连接列,且关联后再对acinv_07.fiscal_year * 100 + acinv_07.fiscal_period过滤,

因此,慢是自然的了。

  那我们是否可以改写后,根据原SQL的意思,我们用Exists改写成如下,核对数据无误

SELECT  acinv_07.id_item ,
        SUM(acinv_07.dec_endqty) dec_endqty
FROM    acinv_07
WHERE   EXISTS ( SELECT NULL
                 FROM   ctlm1101
                 WHERE  flag_curr = 'Y'
                        AND id_oprcode = 'acinv'
                        AND acinv_07.id_wh = ctlm1101.id_table
                        AND ctlm1101.fiscal_year = acinv_07.fiscal_year
                        AND ctlm1101.fiscal_period = acinv_07.fiscal_period )
GROUP BY acinv_07.id_item
View Code

  改写之后,执行计划走的是哈希连接,数据一查询是秒出。我们来分析改写后的执行计划,

小表ctlm1101作为哈希连接的驱动表,id_table,fiscal_year,fiscal_period作为连接列,和大表acinv_07

关联时过滤了大部分数据,所以通过哈希匹配可以快速返回所有结果。

 

推荐阅读