日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql外部排序_深入浅出MySQL优先队列(你一定会踩到的order by limit 问题)

發布時間:2025/3/8 数据库 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql外部排序_深入浅出MySQL优先队列(你一定会踩到的order by limit 问题) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0.先拋問題

假設字段category無索引且有重復值,order by category 和 limit 組合使用的結果會和預期不符。

問題復現:

表結構(就是兩個字段)

CREATE?TABLE?`ratings`?(

`id`?int(11)?NOT?NULL?AUTO_INCREMENT,

`category`?int(11)?DEFAULT?NULL,

PRIMARY?KEY?(`id`)

)?ENGINE=InnoDBAUTO_INCREMENT=11DEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_general_ci;

對所有數據按category字段排序: select * from ratings order by category;

id

category

1

1

5

1

10

1

3

2

4

2

6

2

9

2

2

3

7

3

8

3

當我們想分頁展示前5條時使用select * from ratings order by category limit 5;

期望得到的ID順序是1 5 10 3 4。

但實際結果如下:

id

category

1

1

10

1

5

1

3

2

4

2

怎么肥似?MySQL 出 Bug 了?

可能有同學遇到過這個問題,百度或谷歌一下解決了,你有沒有想過,你查到的辦法是最優解嗎?別人是怎么得出這個辦法的?MySQL 為什么會這樣做,跟版本有關嗎?

先拋結論:

最優解是后面再加個列值唯一的排序字段,如:order by category,id;

MySQL 為什么這樣做?答案是為了快!(MySQL 5.6及其之后才有此優化)

次優解是對order by后面的category 加索引(為什么是次優解?看完本文你將會有答案);

下面課代表將還原一下這 3 條結論的產出過程。

1. 最優解

If multiple rows have identical values in the ORDER BY columns, the server is free to return those rows in any order, and may do so differently depending on the overall execution plan. In other words, the sort order of those rows is nondeterministic with respect to the nonordered columns.

One factor that affects the execution plan is LIMIT, so an ORDER BY query with and without LIMIT may return rows in different orders.

總結來說就是:

當 ORDER BY 列的字段值存在重復,那么這條 ORDER BY 語句返回的數據順序會因為LIMIT的存在而變得不一樣

這是 MySQL 默認對該場景做的優化,如果你需要保證加不加 LIMIT 順序都要一致,官方也給出了辦法:

If it is important to ensure the same row order with and without LIMIT, include additional columns in the ORDER BY clause to make the order deterministic.

就是在ORDER BY 后面再多加一個排序字段(比如 ID 字段)。

以上描述最早出現在MySQL 5.6文檔中,從這個版本開始,引入了這個針對ORDER BY LIMIT 的優化。

好了, 針對文中的場景,我們只需要select * from ratings order by category,id;即可解決。

那么問題來了,MySQL 為什么要做這么一個看似是 Bug 的優化?

2.MySQL 的 ORDER BY 邏輯

顧名思義,ORDER BY 就是排序。

執行一下explain select * from ratings order by category limit 5;

***************************?1.?row?***************************

id:?1

select_type:?SIMPLE

table:?ratings

partitions:?NULL

type:?ALL

possible_keys:?NULL

key:?NULL

key_len:?NULL

ref:?NULL

rows:?10

filtered:?100.00

Extra:?Using?filesort

1?row?in?set,?1?warning?(0.00?sec)

可以看到 Extra: Using filesort 表示需要排序。

正常情況下, MySQL 會有內存排序和外部排序兩種:

如果待排序的數據量小于sort buffer size,排序就在內存中完成(快速排序);

如果待排序的數據量大于sort buffer size,就使用臨時文件進行外部排序(歸并排序);

很明顯,這兩種排序都是對所有結果全部排序,講道理,不管有沒有LIMIT,都是從排完序的結果中按順序取需要的條數,有沒有LIMIT是不會影響返回的結果順序的。

但是,MySQL 5.6 版本針對 ORDER BY LIMIT做了個小優化(排序字段無索引,且列值不唯一時):優化器在遇到 ORDER BY LIMIT語句的時候,使用了priority queue。

filesort.cc 中有如下偽代碼描述該優化:

while?(get_next_sortkey())

{

if?(using?priority?queue)

push?sort?key?into?queue

else

{

try?to?put?sort?key?into?buffer;

if?(no?free?space?in?sort?buffer)

{

do?{

allocate?new,?larger?buffer;

retry?putting?sort?key?into?buffer;

}?until?(record?fits?or?no?space?for?new?buffer)

if?(no?space?for?new?buffer)

{

sort?record?pointers?(all?buffers);

dump?sorted?sequence?to?'tempfile';

dump?Merge_chunk?describing?sequence?location?into?'chunk_file';

}

}

if?(key?was?packed)

tell?sort?buffer?the?actual?number?of?bytes?used;

}

}

if?(buffer?has?some?elements?&&?dumped?at?least?once)

sort-dump-dump?as?above;

else

don't?sort,?leave?sort?buffer?to?be?sorted?by?caller.

Many?web?customers?have?to?do

"SELECT?...?ORDER?BY?non_index_column?LIMIT?X",

When?X?*??is?smaller?than?sort_buff_size?we?can?use

the?following?algoritm?to?speed?up?the?sort:

-?Create?a?queue?to?hold?'limit'?keys.

-?Scan?through?the?table?and?store?the?first?(last?if?DESC)?keys?in?the?queue

-?Return?values?from?queue

This?is?much?faster?than?the?current?algoritm?that?works?as:

該 WorkLog 中記錄了優化后的效果:10 to 20 times faster than a quicksort(感興趣的同學可以去閱讀原文)。

所以,就是為了快!

MySQL 認為這種場景就是求 TOP N 的問題,使用 priority queue 就能解決。

3.priority queue(優先級隊列)

priority queue 其實就是堆,Java 中有java.util.PriorityQueue類,其本質就是 堆 這種數據結構。

簡單解釋一下什么是堆:

堆是一個完全二叉樹;

堆中每一個節點的值都必須大于等于(大頂堆)或小于等于(小頂堆)其子樹中每個節點的值。

如果 MySQL 使用歸并或快排,需要把所有數據都排好序,再取LIMIT 的前幾條,剩余已排序的數據就白白浪費了。

而采用 priority queue 可以根據 LIMIT的條數維護一個堆,只需要把所有數據在這個堆里過一遍就能得到結果。

使用如下語句可以驗證 MySQL 使用了 priority queue:

SEToptimizer_trace='enabled=on';

select?*?from?ratings?order?by?category?limit?5;

SELECT?*?FROM?`information_schema`.`OPTIMIZER_TRACE`\G;

"filesort_priority_queue_optimization":?{

"limit":?5,

"chosen":?true

},

可以看到 filesort_priority_queue_optimization.chosen = true

下面用流程圖還原一下 priority queue 的執行邏輯(以LIMIT 5為例):

友情提示:圖中的小頂堆以 category 值的大小排序

1.? 取前五條數據構成一個小頂堆:

1.? 取下一行數據(6,2),發現 2 小于當前堆中最大的category 3,于是把(2,3)從堆中刪掉,把(6,2) 入堆:

1.? 重復步驟 2,直至符合查詢條件的數據都經歷過比較入堆,最終堆中數據如圖:

以上就是通過 priority queue 找到 最小的 5 行 category 數據的執行過程。

最后我們將其出堆即可得到結果,每次出堆最小元素后將最后一個元素放入堆頂,按照小頂堆重新堆化,過程如圖:

可以看到,這個結果和select * from ratings order by category limit 5;的輸出一致

4.加索引為什么是次優解

顯然,按照ORDER BY 的邏輯,直接對排序字段加索引也可以省去內存排序步驟,從而解決這個問題。

但索引也不是銀彈,多出來的category索引會增加表的維護成本,如果沒有明顯的業務需要,單純為了繞過這個priority queue的優化而加索引,課代表認為有點得不償失。

尤其是當表數據量非常大的時候,索引的體量會很可觀。而且,針對文中場景,category作為分類字段,重復率會比較高,即使有按分類查詢的業務 SQL ,MySQL 也不一定會選取這條索引。

綜上,針對本場景,個人認為order by category,id才是該問題的最優解。

PS:會不會有人問:關我鳥事,我從沒寫過帶 LIMIT 的 SQL 啊!

難道你寫的 CRUD 功能都不帶分頁的嗎?PageHelper 源碼去了解一下?

5. 總結

本文案例是課代表上線過程中遭遇到的實際問題,咨詢了下周圍同學,有好幾個都遇到過此問題,網上文章大多淺入淺出,讀完有隔靴搔癢之感,無法解答心中疑惑。遂整理此文。

其中涉及 數據結構,PageHelper,MySQL 文檔,相關參考資料羅列在文末,如果有時間能順著文章思路親自讀一遍參考文檔,相信會有更深的收獲。

【編輯推薦】

【責任編輯:龐桂玉 TEL:(010)68476606】

點贊 0

總結

以上是生活随笔為你收集整理的mysql外部排序_深入浅出MySQL优先队列(你一定会踩到的order by limit 问题)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 极品少妇xxx | 激情福利视频 | 丝袜制服中文字幕 | 国产毛片久久久久久久 | 久久久久久在线观看 | 色综合免费视频 | 亚洲美免无码中文字幕在线 | 一区二区在线视频播放 | 日本中文字幕二区 | 999色综合 | 国产中文字幕视频 | 国产一区中文 | 一线毛片 | 麻豆激情网 | av福利网站 | 51精品国自产在线 | 欧美一区二区二区 | 黄色欧美视频 | 亚洲日本三级 | 国产精品久线在线观看 | 成人网战 | 国产精品腿扒开做爽爽爽挤奶网站 | 变态视屏 | 色涩视频在线观看 | 久草免费在线观看 | 天堂va欧美va亚洲va老司机 | 俺也去五月婷婷 | 久久精品国产免费 | 亚洲一区二区三区综合 | 国产视频一区二区在线播放 | 国产不卡毛片 | 操操操综合 | 琪琪av在线 | 人妻少妇精品一区二区 | 91华人在线| 久久久久久久 | 丰满大肥婆肥奶大屁股 | 国产在线二区 | 羞羞漫画在线播放 | 自拍视频在线 | 视频在线播 | 欧美性插视频 | 亚洲综合一区二区 | 国产精品高潮视频 | 在线免费观看污网站 | 精品女同一区二区三区 | 精品三级av | 欧美精品一区二区视频 | 国产乱码精品一区二区三区亚洲人 | 亚洲香蕉av | 欧美乱码精品一区二区三区 | 欧美精品在线免费 | 在线高清av| 日本精品一区视频 | 久久精品蜜桃 | 人妻体内射精一区二区 | 狠狠综合一区 | 动漫av一区 | 亚州男人的天堂 | 韩国伦理在线 | 日本成人在线免费视频 | 91九色视频在线 | 五月天国产在线 | 国产福利在线免费观看 | 免费萌白酱国产一区二区三区 | 亚洲成人免费视频 | 波多野结衣爱爱 | 91九色国产在线 | 麻豆成人91精品二区三区 | 日本一区二区视频在线 | 亚洲美女在线视频 | 欧美日韩一区二区三区视频 | 日本高清视频www | 户外少妇对白啪啪野战 | 亚洲深夜福利 | 一区二区三区小视频 | 亚洲Av无码成人精品区伊人 | 成人h动漫精品一区 | 精品人妻一区二区免费 | 欧美 日韩 成人 | 中文字幕第12页 | 黄色网页免费在线观看 | 日韩精品欧美精品 | 久久午夜鲁丝 | 99热在线国产 | 久久久国产精品久久久 | 免费观看久久久 | 黄黄的视频在线观看 | 国产丝袜视频在线 | 无码久久av一区二区三区 | 欧美熟妇一区二区 | 99精品乱码国产在线观看 | 91精品国产99久久久久久红楼 | 老妇free性videosxx| 黄色大毛片 | 中文字幕电影一区 | 人妻熟妇又伦精品视频a | 中文字幕 亚洲一区 | 精品国产一区二区三区久久久蜜月 |