1. 程式人生 > >sql優化實戰:從6秒+到2秒(使用索引)

sql優化實戰:從6秒+到2秒(使用索引)

今天客服反饋 客戶在前兩天查詢一個移動端報表時報錯了。

我看了一下報錯資訊,大致是timeout,這種錯誤基本可以確定是由於查詢時間超過閥值(一般為3秒)。

sql程式碼如下:

SELECT  hh.EMP_ID ,
        hh.STORE_ID ,
        hh.pn1 ,
        SUM(hh.numb) numb ,
        SUM(hh.SJ) sj ,
        NULL zb
FROM      ( SELECT  po.EMP_ID ,
                    v.STORE_ID ,
                    v.UPLOAD_DATE ,
                    i.PN1 ,
                    CAST(iv.ITEM1 AS NUMERIC) numb ,
                    CAST(iv.ITEM1 AS NUMERIC)
                    * CAST(p.PRICE AS NUMERIC(10, 2)) SJ 
            FROM      TB_DR v WITH ( NOLOCK )
                    INNER HASH JOIN TB_DR_ITEM iv WITH ( NOLOCK ) ON iv.MAIN_ID = v.ID
                    INNER JOIN tb_org o WITH ( NOLOCK ) ON v.emp_id = o.emp_id 
                    INNER JOIN tb_org po WITH ( NOLOCK ) ON po.org_ID = o.PARENT_ORG_ID
                    INNER JOIN tb_PROD p WITH ( NOLOCK ) ON p.PROD_ID = iv.PROD_ID
                    INNER JOIN tb_DI i WITH ( NOLOCK ) ON i.DICT_ITEM_ID = p.BRAND_ID
            WHERE   LEFT(v.bdate, 7) = CONVERT(VARCHAR(7), GETDATE(), 120) 
                    AND v.CODE IN ( 'SB001', 'SB002','SB003')
                    AND po.emp_id = 12345
        ) hh
GROUP BY  hh.EMP_ID ,
        hh.STORE_ID ,
        hh.pn1
執行時間:大概是6秒。
表資訊:tb_dr大概是500w條,tb_dr_item大概是2800w條資料,其他的表基本上都是幾千條。

結果集:大致返回50條。

優化:由於tb_dr已有bdate欄位的索引,沒有看執行計劃,但是由於 left 函式作用在bdate,導致這個索引用不上,同時考慮到tb_dr和tb_dr_item表主表-子表,子表通過main_id和主表的id關聯,所以在join時不應該用hash,就算要用也應該是loop,所以改為:

SELECT  hh.EMP_ID ,
        hh.STORE_ID ,
        hh.pn1 ,
        SUM(hh.numb) numb ,
        SUM(hh.SJ) sj ,
        NULL zb
FROM      ( SELECT  po.EMP_ID ,
                    v.STORE_ID ,
                    v.UPLOAD_DATE ,
                    i.PN1 ,
                    CAST(iv.ITEM1 AS NUMERIC) numb ,
                    CAST(iv.ITEM1 AS NUMERIC)
                    * CAST(p.PROD_PRICE AS NUMERIC(10, 2)) SJ 
            FROM      TB_R v WITH ( NOLOCK )
                    INNER HASH JOIN TB_DR_ITEM iv WITH ( NOLOCK ) ON iv.MAIN_ID = v.ID
                    INNER JOIN tb_org o WITH ( NOLOCK ) ON v.emp_id = o.emp_id 
                    INNER JOIN tb_org po WITH ( NOLOCK ) ON po.org_ID = o.PARENT_ORG_ID
                    INNER JOIN tb_PROD p WITH ( NOLOCK ) ON p.PROD_ID = iv.PROD_ID
                    INNER JOIN tb_DI i WITH ( NOLOCK ) ON i.DICT_ITEM_ID = p.BRAND_ID
            WHERE   v.bdate like CONVERT(VARCHAR(7), GETDATE(), 120) +'%'
                    AND v.FUNC_CODE IN ( 'TB_006', 'TB_006_AT05',
                                            'TB_006_AT06',
                                            'TB_006_AT07',
                                            'TB_006_AT08',
                                            'TB_005_AT02',
                                            'TB_005_AT03',
                                            'TB_005_AT04',
                                            'TB_005_AT05',
                                            'TB_005_AT06',
                                            'TB_005_AT07',
                                            'TB_005_AT08',
                                            'TB_005_AT09' )
                    AND po.emp_id = 12345
        ) hh
GROUP BY  hh.EMP_ID ,
        hh.STORE_ID ,
        hh.pn1

其中最主要的是把LEFT(v.bdate, 7) = CONVERT(VARCHAR(7), GETDATE(), 120)  改為 v.biz_date like CONVERT(VARCHAR(7), GETDATE(), 120) +'%',這樣索引就能用上了。

查詢速度從6秒降為2秒大笑