你們好我是不同的科技宅,天天進步一點點,體驗不同的生活,今天咱們聊一聊Mysql大表查詢優化,前段時間應急羣有客服反饋,會員管理功能沒法按到店時間、到店次數、消費金額 進行排序。通過排查發現是Sql執行效率低,而且索引效率低下。web
商戶反饋會員管理功能沒法按到店時間、到店次數、消費金額 進行排序,一直轉圈圈或轉完無變化,商戶要以此數據來作活動,比較着急,請儘快處理,謝謝。sql
merchant_member_info
7000W條數據。 member_info
3000W。 app
不要問我爲何不分表,改動太大,無能爲力。性能
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
優化前3d
優化後
type由index -> ref
ref由 null -> const
TOP | 優化前 | 優化後 |
---|---|---|
到店時間-降序 | 0.274s | 0.003s |
到店時間-升序 | 11.245s | 0.003s |
執行的注意事項:
因爲表中的數據量太大,請在晚上進行執行,而且須要分開執行。
# 刪除近期消費時間索引
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 |
優化思路:先走覆蓋索引定位到,須要的數據行的主鍵值,而後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
複製代碼
若是以爲對你有幫助,能夠多多評論,多多點贊哦,也能夠到個人主頁看看,說不定有你喜歡的文章,也能夠隨手點個關注哦,謝謝。