1. MySQL | 使用 limit 優(yōu)化查詢和防止SQL被優(yōu)化

        共 3028字,需瀏覽 7分鐘

         ·

        2021-05-28 11:41


        Table of Contents

        查詢優(yōu)化1.1 最大值和最小值的優(yōu)化1.2 優(yōu)化 limit 分頁1.2.1 使用關聯(lián)查詢優(yōu)化1.2.2 使用范圍查詢1.2.3 利用唯一自增序列進行查詢防止被優(yōu)化參考

        查詢優(yōu)化

        1.1 最大值和最小值的優(yōu)化

        對于 MIN()MAX() 查詢,MySQL 的優(yōu)化做的并不是太好,例如

        select MIN(idFROM film where name = '西游記'

        假設表 film 數(shù)據(jù)如下:

        idnameprice
        1英雄本色12
        2哪吒傳奇14
        3西游記34
        4水滸傳23
        5紅樓夢34
        6紅與黑2
        7紅與黑4
        8美人魚23
        9爸爸歸來23
        10我是誰12
        11喜羊羊56
        12西游記67

        其中 id 為主鍵并自增,namevarchar 且沒有索引

        因為 name 沒有索引,因為 MySQL 將會進行一次全表掃描。因為 id 為自增,那么我們可以當作,第一次找到 name='西游記'時,id 就為我們想要的結果,此時我們可以改寫 SQL 為:

        select id FROM film where name = '西游記' limit 1;

        此時當查到第一條記錄時,就會停止繼續(xù)查詢,獲得更高的性能。

        1.2 優(yōu)化 limit 分頁

        在系統(tǒng)進行分頁操作的時候,當偏移量大時,例如:limit 10000,20 時,MySQL 需要查詢 10020 條記錄然后只返回 20 記錄,前面的記錄全部被舍棄,這樣的代價非常高

        SELECT idname, price FROM file LIMIT 10000 OFFSET 20

        上面的 SQL 我想是分頁常規(guī)的寫法,寫法沒有什么錯誤,正如上面說到,浪費了大量的性能。

        1.2.1 使用關聯(lián)查詢優(yōu)化

        優(yōu)化此類查詢一個簡單的方法就是盡可能地使用索引覆蓋掃描,而不是查詢所有的列,然后根據(jù)需要做一次關聯(lián)操作再返回所需的列。對于偏移大的時候,這樣做的效率提升非常大。

        SELECT
            idname, price
        FROM film
        INNER JOIN (
            SELECT id
            FROM film
            LIMIT 10000 OFFSET 20
            ) AS LIM USING(id)

        1.2.2 使用范圍查詢

        有時候可以將 LIMIT 轉(zhuǎn)化為已知位置的查詢,讓 MySQL 通過范圍掃描獲得到對應的結果。例如,如果在一個位置列上有索引,并且預先計算出了邊界值,則改寫查詢?yōu)椋?/p>

        SELECT idname, price
        FROM film
        WHERE position BETWEEN 10000 AND 10020
        ORDER BY position

        1.2.3 利用唯一自增序列進行查詢

        這里的唯一自增序列可以是自增 id 主鍵,也可以其他的具有唯一和升序的數(shù)字即可

        在前面的思路中,我們考慮的都是傳入頁數(shù)和每頁數(shù)量,在一些操作中可以改為傳入上一次查詢到的自增序列,然后往后查詢對應的每頁數(shù)量即可。

        例如原來要求前端傳入頁數(shù)(pageIndex)和 每頁數(shù)量(pageSize), 此時的 SQL 為

        select * from film 
        limit (pageIndex -1) * pageSize OFFSET pageIndex * pageSize

        如果改為讓前端傳入最后一次查詢到結果的 自增序列(sid) 和 每頁數(shù)量(pageSize)

        比如這時的自增序列(sid) 就是 film 的 id, 則 SQL 可以改寫成

        select * from film 
        where id > sid
        limit pageSize

        當查第一頁的時候,sid 傳入 0 即可,查第二頁的時候,傳入獲取第一頁時最后得到 id 即可

        防止被優(yōu)化

        在寫 SQL 的時候,除了要考慮優(yōu)化 SQL 降低執(zhí)行時間外,有時還要防止 SQL 被 MySQL 本身給你優(yōu)化掉,造成執(zhí)行結果和你想象的不一樣。

        在 MySQL 使用 group by 語句進行查詢時,當有多條數(shù)據(jù)都滿足時,會顯示第一條數(shù)據(jù)例如:

        假設表 film 數(shù)據(jù)如下:

        idnameprice
        1英雄本色12
        2哪吒傳奇14
        3西游記34
        4水滸傳23
        5唐探380
        6唐探350

        則執(zhí)行SQL select * from film group by name, 則結果為:

        idnameprice
        1英雄本色12
        2哪吒傳奇14
        3西游記34
        4水滸傳23
        5唐探380

        但在一些數(shù)據(jù)重復時,我們往往想要最后一條數(shù)據(jù), 這是我們會想到通過子查詢的形式先排序后group by 如下:

        select *
        from ( select * from film order by id descas film_ordered
        group by name;

        執(zhí)行后發(fā)現(xiàn)結果沒變, 這是因為 MySQL5.7 會對子查詢進行優(yōu)化,認為子查詢中的 order by 可以進行忽略,只要Derived table里不包含如下條件就可以進行優(yōu)化:

        • UNION clause

        • GROUP BY

        • DISTINCT

        • Aggregation

        • LIMIT or OFFSET

        根據(jù)上面說明,我們可以使用 limit 阻止子查詢優(yōu)化,改寫后SQL

        select *
        from ( select * from film order by id desc limit 10000000as film_ordered
        group by name;

        這樣結果就符合我們想要的了


        如果微信不太適合看文檔,可以 https://www.yuque.com/shuangguidaidan/growth 查看

        瀏覽 88
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 在线你懂得 | 91无码人妻精品一区二 区蜜桃 | 97麻豆国产传媒成人影片 | 91亚洲精华 | 97超级碰碰碰精品色视频在线观看 |