多表關聯group by優化:去除Using temporary; Using filesort

  最近因爲項目很趕,很久沒寫博客了,今天算是已經把項目進度超前完成了,寫一個今天解決的SQL優化問題。

  這次優化花了半小時,但很值得,之前作爲一個單純後端,很少關注SQL效率,但是自從上個項目當上臨時DBA後,或多或少的都會關注自己書寫的SQL執行計劃。

   原始第一映像寫出的腳本: 

   EXPLAIN
SELECT
    service_id,service_name,count(1)
FROM
    order_orders t1,
    order_user_coupon t2
WHERE
    t1.coupon_id = t2.coupon_id
AND t1.merchant_id = '1'
AND (
    t1.update_time BETWEEN str_to_date(
        '2019-01-01 00:00:00',
        '%Y-%m-%d %H:%i:%s'
    )
    AND str_to_date(
        '2019-03-06 00:00:00',
        '%Y-%m-%d %H:%i:%s'
    )
)
group by service_id;

執行計劃如下:

兩張表各種加索引,沒用,後來仔細分析了一下,之所以產生臨時表,是因爲整個查詢過程,你首先要通過關聯條件查詢出一個結果集,然後再根據這個結果集進行分組排序,自然就會有臨時表和文件排序。

 

第二次優化腳本如下:

EXPLAIN SELECT
    t1.service_id,
    t1.service_name,
    count(1)
FROM
    order_user_coupon t1
WHERE
    t1.coupon_id in(
        SELECT
            coupon_id
        FROM
            order_orders t2
        WHERE
     t2.merchant_id = '1'
        AND t2.update_time BETWEEN str_to_date(
            '2019-01-01 00:00:00',
            '%Y-%m-%d %H:%i:%s'
        )
        AND str_to_date(
            '2019-03-06 00:00:00',
            '%Y-%m-%d %H:%i:%s'
        )
    )
GROUP BY
    t1.service_id;

本想着,避免了關聯查詢,使用t1表的結果集做分組,應該能避免臨時表及文件排序,結果沒想到in中的查詢使用了,好吧,廢棄。

 

第三次優化如下:

EXPLAIN SELECT
    t1.service_id,
    t1.service_name,
    count(1)
FROM
    order_user_coupon t1
WHERE
    EXISTS (
        SELECT
            coupon_id
        FROM
            order_orders t2
        WHERE
            t1.coupon_id = t2.coupon_id
        AND t2.merchant_id = '1'
        AND t2.update_time BETWEEN str_to_date(
            '2019-01-01 00:00:00',
            '%Y-%m-%d %H:%i:%s'
        )
        AND str_to_date(
            '2019-03-06 00:00:00',
            '%Y-%m-%d %H:%i:%s'
        )
    )
GROUP BY
    t1.service_id;

思路:以條件篩選出t2表中數據,以少量數據作爲驅動,查詢t1表關聯數據,之後基於t1表的結果集進行group by操作。

完美解決!

 

最後優化索引:

1、 group by 後的字段一定是要添加索引的,否則還是 臨時表進行排序;

2、 這裏merchant_id基本能完成大部分數據篩選了,所以添加merchant_id的索引,而不再添加coupon_id索引。

最終結果如下:

Using Index Condition

     在MySQL 5.6版本後加入的新特性(Index Condition Pushdown);會先條件過濾索引,過濾完索引後找到所有符合索引條件的數據行,隨後用 WHERE 子句中的其他條件去過濾這些數據行;

夠用了,完美!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章