常被忽視的SQL錯誤用法/語法執行先後次序 (壓低資料維度/效率/速度 提升/加速/加快)

常被忽視的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錯誤用法/語法執行先後次序 (壓低資料維度/效率/速度 提升/加速/加快)

  1. 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]

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *