常被忽視的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]