線上千萬級大表排序優化

前言

  你們好我是不同的科技宅,天天進步一點點,體驗不同的生活,今天咱們聊一聊Mysql大表查詢優化,前段時間應急羣有客服反饋,會員管理功能沒法按到店時間、到店次數、消費金額 進行排序。通過排查發現是Sql執行效率低,而且索引效率低下。web

應急問題

  商戶反饋會員管理功能沒法按到店時間、到店次數、消費金額 進行排序,一直轉圈圈或轉完無變化,商戶要以此數據來作活動,比較着急,請儘快處理,謝謝。sql

線上數據量

merchant_member_info 7000W條數據。
member_info 3000W。 app

不要問我爲何不分表,改動太大,無能爲力。性能

問題SQL以下

SELECT
    mui.id,
    mui.merchant_id,
    mui.member_id,
    DATE_FORMAT(
        mui.recently_consume_time,
        '%Y%m%d%H%i%s'
    ) recently_consume_time,
    IFNULL(mui.total_consume_num, 0) total_consume_num,
    IFNULL(mui.total_consume_amount, 0) total_consume_amount,
    (
        CASE
        WHEN u.nick_name IS NULL THEN
            '會員'
        WHEN u.nick_name = '' THEN
            '會員'
        ELSE
            u.nick_name
        END
    ) AS 'nickname',
    u.sex,
    u.head_image_url,
    u.province,
    u.city,
    u.country
FROM
    merchant_member_info mui
LEFT JOIN member_info u ON mui.member_id = u.id
WHERE
    1 = 1
AND mui.merchant_id = '商戶編號'
ORDER BY
    mui.recently_consume_time DESC / ASC
LIMIT 0,
 10
複製代碼

出現的緣由

  通過驗證能夠按照「到店時間」進行降序排序,可是沒法按照升序進行排序主要是查詢太慢了。主要緣由是:雖然該查詢使用創建了recently_consume_time索引,可是索引效率低下,須要查詢整個索引樹,致使查詢時間過長。測試

DESC 查詢大概須要4s,ASC 查詢太慢耗時未知。優化

爲何降序排序快和而升序慢呢?

  由於是對時間創建了索引,最近的時間必定在最後面,升序查詢,須要查詢更多的數據,才能過濾出相應的結果,因此慢。ui

解決方案

目前生產庫的索引

調整索引

  須要刪除index_merchant_user_last_time索引,同時將index_merchant_user_merchant_ids單例索引,變爲 merchant_id,recently_consume_time組合索引。url

調整結果(準生產)

調整先後結果對比(準生產)

 測試數據

merchant_member_info 有902606條記錄。
member_info 表有775條記錄。 spa

SQL執行效率

優化前3d

優化後

type由index -> ref

ref由 null -> const

TOP 優化前 優化後
到店時間-降序 0.274s 0.003s
到店時間-升序 11.245s 0.003s

調整索引須要執行的SQL

執行的注意事項:
因爲表中的數據量太大,請在晚上進行執行,而且須要分開執行。 

# 刪除近期消費時間索引
ALTER TABLE merchant_member_info DROP INDEX index_merchant_user_last_time;

# 刪除商戶編號索引
ALTER TABLE merchant_member_info DROP INDEX index_merchant_user_merchant_ids;

# 創建商戶編號和近期消費時間組合索引
ALTER TABLE merchant_member_info ADD INDEX idx_merchant_id_recently_time (`merchant_id`,`recently_consume_time`);
複製代碼

經詢問,重建索引花了30分鐘。

最終的分頁查詢優化

  上面的sql雖然通過調整索引,雖然能達到較高的執行效率,可是隨着分頁數據的不斷增長,性能會急劇降低。

分頁數據 查詢時間 優化後
limit 0,10 0.003s 0.002s
limit 10,10 0.005s 0.002s
limit 100,10 0.009s 0.002s
limit 1000,10 0.044s 0.004s
limit 9000,10 0.247s 0.016s

最終的sql

優化思路:先走覆蓋索引定位到,須要的數據行的主鍵值,而後INNER JOIN 回原表,取到其餘數據。

SELECT
    mui.id,
    mui.merchant_id,
    mui.member_id,
    DATE_FORMAT(
        mui.recently_consume_time,
        '%Y%m%d%H%i%s'
    ) recently_consume_time,
    IFNULL(mui.total_consume_num, 0) total_consume_num,
    IFNULL(mui.total_consume_amount, 0) total_consume_amount,
    (
        CASE
        WHEN u.nick_name IS NULL THEN
            '會員'
        WHEN u.nick_name = '' THEN
            '會員'
        ELSE
            u.nick_name
        END
    ) AS 'nickname',
    u.sex,
    u.head_image_url,
    u.province,
    u.city,
    u.country
FROM
    merchant_member_info mui
INNER JOIN (
    SELECT
        id
    FROM
        merchant_member_info
    WHERE
        merchant_id = '商戶ID'
    ORDER BY
        recently_consume_time DESC
    LIMIT 9000,
    10
AS tmp ON tmp.id = mui.id
LEFT JOIN member_info u ON mui.member_id = u.id
複製代碼

結尾

  若是以爲對你有幫助,能夠多多評論,多多點贊哦,也能夠到個人主頁看看,說不定有你喜歡的文章,也能夠隨手點個關注哦,謝謝。

相關文章
相關標籤/搜索