最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL Limit執(zhí)行過程分析探索

 更新時間:2022年12月12日 15:06:16   作者:愛吃南瓜糕的北絡(luò)  
limit是MySql的內(nèi)置函數(shù),一般用于查詢表中記錄的條數(shù),作用是用于限制查詢條數(shù),下面這篇文章主要給大家介紹了關(guān)于SQL中l(wèi)imit函數(shù)語法與用法的相關(guān)資料,詳細(xì)講了MySQL Limit執(zhí)行過程

故事還得從下面的圖說起:

what? 兩條sql執(zhí)行結(jié)果的id列居然不一致。。。。。。

一、LIMIT 處理過程

為了故事的順利發(fā)展,我們得先創(chuàng)建一張表:

CREATE TABLE `t_null_index` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `key1` char(1) DEFAULT NULL,
  `common_field` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_key1` (`key1`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3

表 t_null_index 包含3個列,id列是主鍵,key1列是二級索引列。表中包含9999條數(shù)據(jù)。

mysql> select * from t_null_index order by key1 limit 1;
+-------+------+----------------------------------+
| id    | key1 | common_field                     |
+-------+------+----------------------------------+
| 10019 | a    | a9ecd8f845cd4e6791e99af406e075c1 |
+-------+------+----------------------------------+
1 row in set (0.00 sec)
mysql> explain select * from t_null_index order by key1 limit 1;
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------+
| id | select_type | table        | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t_null_index | NULL       | index | NULL          | idx_key1 | 4       | NULL |    1 |   100.00 | NULL  |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

當(dāng)我們執(zhí)行上面的這條sql,是使用了 idx_key1 二級索引,這個好理解,因為在二級索引idx_key1中,key1列是有序的。而查詢是要取按照key1列排序的第1條記錄,那MySQL只需要從idx_key1中獲取到第一條二級索引記錄,然后直接回表得到完整聚簇索引的記錄返回客戶端即可。

但是如果我們把上邊語句的 limit 1 換成 limit 5000, 1,效果會如何?

mysql> select * from t_null_index order by key1 limit 5000, 1;
+-------+------+----------------------------------+
| id    | key1 | common_field                     |
+-------+------+----------------------------------+
| 10125 | e    | e90499ca17b44727ab44a08c1cf609e8 |
+-------+------+----------------------------------+
1 row in set (0.00 sec)
mysql> explain select * from t_null_index order by key1 limit 5000, 1;
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | t_null_index | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9847 |   100.00 | Using filesort |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.01 sec)

當(dāng) limit 1 換成 limit 5000, 1 后,我們發(fā)現(xiàn)沒有使用 idx_key1 二級索引,反而使用了全表掃描,并且進(jìn)行 Using filesort。

開始我很不理解,limit 5000, 1 也可以使用二級索引 idx_key1啊,我們可以先掃描到第5001條二級索引記錄,對5001條二級索引記錄通過主鍵id回表取得完成聚簇索引記錄不就好了嗎?這樣的代價也比全表掃描+filesort牛批啊。

Limit具體是怎么搞?

我們知道,MySQL 內(nèi)部其實是分為 server層 和 存儲引擎層,具體 server層和存儲引擎層具體的交互這里就不說了。

對于limit的操作,MySQL是在server層準(zhǔn)備向客戶端發(fā)送記錄的時候才會去處理limit子句中的內(nèi)容。

select * from t_null_index order by key1 limit 5000, 1;

如果使用 idx_key1 索引執(zhí)行上述查詢,那么MySQL會這樣處理:

(1)server層向InnoDB要第1條記錄,InnoDB從idx_key1中獲取到第1條二級索引記錄,然后進(jìn)行回表操作得到完整的聚簇索引記錄,然后返回給server層。server層準(zhǔn)備將其發(fā)送給客戶端,此時發(fā)現(xiàn)還有個limit 5000, 1的要求,意味著符合條件的記錄中的第5001條才可以返回給客戶端,則不能將記錄返回給客戶端,同時會先記錄下當(dāng)前是第1條。

(2)server層再向InnoDB要下一條記錄,InnoDB再根據(jù)二級索引記錄的next_record屬性找到下一條二級索引記錄,再次進(jìn)行回表得到完整的聚簇索引記錄返回給server層。server層再將其發(fā)送給客戶端的時候發(fā)現(xiàn)當(dāng)前記錄仍然不是5001條,所以就放棄了將記錄發(fā)送給客戶端,同時將記錄數(shù)+1。

(3)。。。重復(fù)上述操作

(4)直到server層發(fā)現(xiàn)InnoDB返回的聚簇索引記錄是5001條的時候,server層才會將InnoDB返回的完整聚簇索引記錄發(fā)送給客戶端。

從上述過程中我們可以看出,由于MySQL中是server層實際向客戶端發(fā)送記錄前才會判斷l(xiāng)imit子句是否符合要求,所以如果使用二級索引執(zhí)行上述查詢的話,意味著需要進(jìn)行5001次回表操作。server層在執(zhí)行執(zhí)行計劃分析的時候會覺得執(zhí)行這么多次回表的成本太大了,還不如直接 全表掃描+filesort 快呢,所以就選擇了 全表掃描+filesort 執(zhí)行查詢。

二、開始的圖

說著說著,差點忘記了故事的前奏的圖了??

奇怪了?為什么都是 limit 5000,1,而兩條sql執(zhí)行結(jié)果的id列居然不一致,我們來看一下兩條sql的執(zhí)行計劃:

mysql> explain select id from t_null_index limit 5000, 1;
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table        | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_null_index | NULL       | index | NULL          | idx_key1 | 4       | NULL | 9847 |   100.00 | Using index |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from t_null_index limit 5000, 1;
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t_null_index | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9847 |   100.00 | NULL  |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

通過執(zhí)行計劃,我們可以看出 select id from t_null_index limit 5000, 1;這條sql執(zhí)行過程采用了idx_key1,我們上面說到 limit 5000, 1 這個條件意味著會進(jìn)行5001次回表操作,為什么這里又走了 idx_key1 索引呢?

其實,由于 select id 查詢的查詢列表只有一個 id 列,而 idx_key1 索引的葉子節(jié)點包含了 索引列key1+主鍵id的信息,故MySQL可以通過僅掃描二級索引idx_key1,然后無需回表操作直接就可以獲取到想要的id列并且返回server層,server層再判斷是否滿足第5001條記錄,如果不滿足,再向InnoDB要下一條記錄,直到滿足為止。這樣就省去了5001條記錄的回表操作,從而大大提升了查詢效率。

那到底為啥兩條sql執(zhí)行結(jié)果的id列值不一樣?

我們來畫一畫 idx_key1索引的示意圖,如圖所示:

通過圖上,我們可以看出 idx_key1 索引B+樹的葉子節(jié)點,根據(jù)key1值由左向右升序排列,當(dāng)key1列相同的節(jié)點,則按照id升序由左向右排序。

mysql> explain select id from t_null_index limit 5000, 1;
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table        | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t_null_index | NULL       | index | NULL          | idx_key1 | 4       | NULL | 9847 |   100.00 | Using index |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

對于上述SQL,由于掃描二級索引 idx_key1,其實結(jié)果集是按照 key1 和 id 這兩個鍵進(jìn)行排序的,可以通過 select * from t_null_index order by key1, id limit 5000, 1; 來驗證結(jié)果的id列是否和上面圖中的SQL結(jié)果一致。而對于select * from t_null_indexlimit 5000, 1; 該SQL由于走全表掃描并且默認(rèn)按照主鍵id升序排序,兩條SQL執(zhí)行的排序規(guī)則不一致,所以就會導(dǎo)致兩條結(jié)果的id列值不一致。

通過上圖,我們可以看出,掃描 idx_key1 索引列的SQL 和 顯示 order by key1,id 的SQL的執(zhí)行結(jié)果id列值是相同的。

那如果顯示對 select * from t_null_index order by key1 limit 5000, 1; 結(jié)果會如何?

通過執(zhí)行結(jié)果,我們可以看出掃描 idx_key1 索引列的SQL 和 顯示 order by key1 的SQL的執(zhí)行結(jié)果id列值還是不相同的。

根據(jù)前面我們的分析,我們知道 select id from t_null_index limit 5000, 1;會通過掃描二級索引 idx_key1 來獲得結(jié)果集,并且結(jié)果集是按照 key1 和 id 這兩個鍵進(jìn)行排序的。而對于 select * from t_null_index order by key1 limit 5000, 1; 這條SQL執(zhí)行會直接全表掃描后再在引擎層根據(jù)key1進(jìn)行文件堆排序。這種排序的結(jié)果集存在根據(jù)key1升序的情況下,相同的key1,id列可能是亂序,所以就會出現(xiàn)圖中兩個值不相等的情況。

附:select * from t_null_index order by key1 limit 5000, 1; 執(zhí)行計劃

mysql> explain select * from t_null_index order by key1 limit 5000, 1;
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | t_null_index | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9847 |   100.00 | Using filesort |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

附:select * from t_null_index order by key1 limit 4990, 20; 出現(xiàn)亂序的情況

到此這篇關(guān)于MySQL Limit執(zhí)行過程分析探索的文章就介紹到這了,更多相關(guān)MySQL Limit內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 這種sql寫法真的會導(dǎo)致索引失效嗎

    這種sql寫法真的會導(dǎo)致索引失效嗎

    這篇文章主要給大家介紹了關(guān)于網(wǎng)上流傳的某種sql寫法會導(dǎo)致索引失效的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用sql具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • MySQL主從復(fù)制數(shù)據(jù)同步的實現(xiàn)步驟

    MySQL主從復(fù)制數(shù)據(jù)同步的實現(xiàn)步驟

    MySQL主從復(fù)制是一種數(shù)據(jù)同步技術(shù),通過將數(shù)據(jù)從主數(shù)據(jù)庫服務(wù)器復(fù)制到一個或多個從數(shù)據(jù)庫服務(wù)器來實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • Mysql如何查詢近30天活躍用戶數(shù)

    Mysql如何查詢近30天活躍用戶數(shù)

    這篇文章主要介紹了Mysql查詢近30天活躍用戶數(shù),本文通過實例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • 基于Mysql存儲引擎的深入分析

    基于Mysql存儲引擎的深入分析

    本篇文章是對Mysql存儲引擎進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • MySql中使用INSERT INTO語句更新多條數(shù)據(jù)的例子

    MySql中使用INSERT INTO語句更新多條數(shù)據(jù)的例子

    這篇文章主要介紹了MySql中使用INSERT INTO語句更新多條數(shù)據(jù)的例子,MySQL的特有語法,需要的朋友可以參考下
    2014-06-06
  • 詳解Navicat遠(yuǎn)程連接mysql很慢

    詳解Navicat遠(yuǎn)程連接mysql很慢

    這篇文章主要介紹了詳解Navicat遠(yuǎn)程連接mysql很慢(以及數(shù)據(jù)庫連接報錯"Too many connections")解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • mysql中影響數(shù)據(jù)庫性能的因素講解

    mysql中影響數(shù)據(jù)庫性能的因素講解

    在本篇文章中我們給大家講述了mysql中影響性能的因素以及相關(guān)知識點內(nèi)容,有興趣的朋友參考下。
    2018-09-09
  • Mac環(huán)境mysql5.7.21 utf8編碼問題及解決方案

    Mac環(huán)境mysql5.7.21 utf8編碼問題及解決方案

    本篇教程給大家簡單介紹下Mac環(huán)境mysql5.7.21 utf8編碼問題及解決方案,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2018-03-03
  • MySQL的id關(guān)聯(lián)和索引使用的實際優(yōu)化案例

    MySQL的id關(guān)聯(lián)和索引使用的實際優(yōu)化案例

    這篇文章主要介紹了MySQL的id關(guān)聯(lián)實際優(yōu)化案例,關(guān)聯(lián)和索引一直是MySQL常見的可優(yōu)化大塊兒,需要的朋友可以參考下
    2015-05-05
  • 淺談mysql 針對單張表的備份與還原

    淺談mysql 針對單張表的備份與還原

    下面小編就為大家?guī)硪黄獪\談mysql 針對單張表的備份與還原。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03

最新評論

周宁县| 巴东县| 汤原县| 澜沧| 大化| 甘谷县| 吴堡县| 临汾市| 根河市| 湛江市| 石楼县| 蓬安县| 昌黎县| 阿合奇县| 澄迈县| 大同县| 若尔盖县| 修文县| 隆昌县| 晋城| 高要市| 侯马市| 舞阳县| 鲁山县| 泉州市| 阜新市| 永靖县| 武功县| 庆阳市| 壤塘县| 土默特右旗| 汤原县| 珠海市| 许昌县| 青川县| 鹤峰县| 屏东市| 开封市| 曲阳县| 辰溪县| 景宁|