常被忽視的SQL錯誤用法/語法執行先後次序 (壓低資料維度/效率/速度 提升/加速/加快)
常被忽視的SQL錯誤用法/語法執行先後次序 (壓低資料維度/效率/速度 提升/加速/加快)
資料來源:https://mp.weixin.qq.com/s?__biz=MzA3MTM3NTA5Ng==&mid=2651062028&idx=4&sn=7603d62c6c580daf52800bf576b11ecd&chksm=84d9de9bb3ae578d521aa5a27c0f951a59fb9a182f4bc13e1ec309c4116332373dfb33a4bde0&scene=0&xtrack=1&key=025fc9d00514bc5b5fd803dc13535ab81f3261230f385570d4f3bb3f53ebb74e7ffc717adda778689abc5857316d899c9c9cacafe3f7bc7813095e146849438bb7791d526f189567277d5a58793572e5&ascene=1&uin=MjIwODk2NDgxNw%3D%3D&devicetype=Windows+10&version=62060833&lang=zh_TW&pass_ticket=1AMJ6z41rnWl0xV806qMh%2BsjvZ9MJckpAWxn%2B1d9Yh%2BOyq0IxmMnjMHdmWYT8GHN
▲SQL執行順序[由上而下]
FROM <left_table> ON <join_condition> <join_type> JOIN <right_table> WHERE <where_condition> GROUP BY <group_by_list> HAVING <having_condition> SELECT DISTINCT <select_list> ORDER BY <order_by_condition> LIMIT <limit_number>
▲LIMIT語句[使用前儘量用WHERE把BASE筆數壓低]
SELECT * FROM operation WHERE type = 'SQLStats' AND name = 'SlowLog' ORDER BY create_time LIMIT 1000, 10; SELECT * FROM operation WHERE type = 'SQLStats' AND name = 'SlowLog' AND create_time > '2017-03-16 14:00:00' ORDER BY create_time LIMIT 10;
▲關聯更新,刪除[用JOIN取代WHERE]
UPDATE operation o SET status = 'applying' WHERE o.id IN (SELECT id FROM (SELECT o.id, o.status FROM operation o WHERE o.group = 123 AND o.status NOT IN ( 'done' ) ORDER BY o.parent, o.id LIMIT 1) t); UPDATE operation o JOIN (SELECT o.id, o.status FROM operation o WHERE o.group = 123 AND o.status NOT IN ( 'done' ) ORDER BY o.parent, o.id LIMIT 1) t ON o.id = t.id SET status = 'applying'
▲混合排序[使用UNION ALL+虛擬表取代單一WHERE]
SELECT * FROM my_order o INNER JOIN my_appraise a ON a.orderid = o.id ORDER BY a.is_reply ASC, a.appraise_time DESC LIMIT 0, 20 SELECT * FROM ((SELECT * FROM my_order o INNER JOIN my_appraise a ON a.orderid = o.id AND is_reply = 0 ORDER BY appraise_time DESC LIMIT 0, 20) UNION ALL (SELECT * FROM my_order o INNER JOIN my_appraise a ON a.orderid = o.id AND is_reply = 1 ORDER BY appraise_time DESC LIMIT 0, 20)) t ORDER BY is_reply ASC, appraisetime DESC LIMIT 20;
▲EXISTS語句[使用JOIN取代EXISTS]
SELECT * FROM my_neighbor n LEFT JOIN my_neighbor_apply sra ON n.id = sra.neighbor_id AND sra.user_id = 'xxx' WHERE n.topic_status < 4 AND EXISTS(SELECT 1 FROM message_info m WHERE n.id = m.neighbor_id AND m.inuser = 'xxx') AND n.topic_type <> 5 SELECT * FROM my_neighbor n INNER JOIN message_info m ON n.id = m.neighbor_id AND m.inuser = 'xxx' LEFT JOIN my_neighbor_apply sra ON n.id = sra.neighbor_id AND sra.user_id = 'xxx' WHERE n.topic_status < 4 AND n.topic_type <> 5
One thought on “常被忽視的SQL錯誤用法/語法執行先後次序 (壓低資料維度/效率/速度 提升/加速/加快)”
https://mp.weixin.qq.com/s/6TThlJICZzgGqad-sX1BrQ
讀取適當的記錄LIMIT M,N,而不要讀多餘的記錄
select id,name from t limit 866613, 20 [X]
使用上述sql語句做分頁的時候,可能有人會發現,隨著表數據量的增加,直接使用limit分頁查詢會越來越慢。
對於 limit m, n 的分頁查詢,越往後面翻頁(即m越大的情況下)SQL的耗時會越來越長,對於這種應該先取出主鍵id,然後通過主鍵id跟原表進行Join關聯查詢。因為MySQL 並不是跳過offset 行,而是取 offset+N 行,然後放棄前offset 行,返回N 行,那當offset 特別大的時候,效率就非常的低下,要么控制返回的總頁數,要么對超過特定閾值的頁數進行SQL 改寫。
優化的方法如下:可以取前一頁的最大行數的id(將上次遍歷到的最末尾的數據ID傳給數據庫,然後直接定位到該ID處,再往後面遍歷數據),然後根據這個最大的id來限制下一頁的起點。比如此列中,上一頁最大的id是866612。sql可以採用如下的寫法:
select id,name from table_name where id> 866612 limit 20 [O]