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

詳細(xì)聊聊MySQL中的LIMIT語句

 更新時間:2021年10月26日 10:43:12   作者:小孩子4919  
大家應(yīng)該都知道LIMIT子句可以被用于強制SELECT語句返回指定的記錄數(shù),這篇文章主要給大家介紹了關(guān)于MySQL中LIMIT語句的相關(guān)資料,需要的朋友可以參考下

最近有多個小伙伴在答疑群里問了小孩子關(guān)于LIMIT的一個問題,下邊我來大致描述一下這個問題。

問題

為了故事的順利發(fā)展,我們得先有個表:

CREATE TABLE t (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    key1 VARCHAR(100),
    common_field VARCHAR(100),
    PRIMARY KEY (id),
    KEY idx_key1 (key1)
) Engine=InnoDB CHARSET=utf8;

表t包含3個列,id列是主鍵,key1列是二級索引列。表中包含1萬條記錄。

當(dāng)我們執(zhí)行下邊這個語句的時候,是使用二級索引idx_key1的:

mysql>  EXPLAIN SELECT * FROM t 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          | idx_key1 | 303     | NULL |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

這個很好理解,因為在二級索引idx_key1中,key1列是有序的。而查詢是要取按照key1列排序的第1條記錄,那MySQL只需要從idx_key1中獲取到第一條二級索引記錄,然后直接回表取得完整的記錄即可。

但是如果我們把上邊語句的LIMIT 1換成LIMIT 5000, 1,則卻需要進行全表掃描,并進行filesort,執(zhí)行計劃如下:

mysql>  EXPLAIN SELECT * FROM t 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       | ALL  | NULL          | NULL | NULL    | NULL | 9966 |   100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

有的同學(xué)就很不理解了:LIMIT 5000, 1也可以使用二級索引idx_key1呀,我們可以先掃描到第5001條二級索引記錄,對第5001條二級索引記錄進行回表操作不就好了么,這樣的代價肯定比全表掃描+filesort強呀。

很遺憾的告訴各位,由于MySQL實現(xiàn)上的缺陷,不會出現(xiàn)上述的理想情況,它只會笨笨的去執(zhí)行全表掃描+filesort,下邊我們嘮叨一下到底是咋回事兒。

server層和存儲引擎層

大家都知道,MySQL內(nèi)部其實是分為server層和存儲引擎層的:

  • server層負(fù)責(zé)處理一些通用的事情,諸如連接管理、SQL語法解析、分析執(zhí)行計劃之類的東西
  • 存儲引擎層負(fù)責(zé)具體的數(shù)據(jù)存儲,諸如數(shù)據(jù)是存儲到文件上還是內(nèi)存里,具體的存儲格式是什么樣的之類的。我們現(xiàn)在基本都使用InnoDB存儲引擎,其他存儲引擎使用的非常少了,所以我們也就不涉及其他存儲引擎了。

MySQL中一條SQL語句的執(zhí)行是通過server層和存儲引擎層的多次交互才能得到最終結(jié)果的。比方說下邊這個查詢:

SELECT * FROM t WHERE key1 > 'a' AND key1 < 'b' AND common_field != 'a';

server層會分析到上述語句可以使用下邊兩種方案執(zhí)行:

  • 方案一:使用全表掃描
  • 方案二:使用二級索引idx_key1,此時需要掃描key1列值在('a', 'b')之間的全部二級索引記錄,并且每條二級索引記錄都需要進行回表操作。

server層會分析上述兩個方案哪個成本更低,然后選取成本更低的那個方案作為執(zhí)行計劃。然后就調(diào)用存儲引擎提供的接口來真正的執(zhí)行查詢了。

這里假設(shè)采用方案二,也就是使用二級索引idx_key1執(zhí)行上述查詢。那么server層和存儲引擎層的對話可以如下所示:

server層:“hey,麻煩去查查idx_key1二級索引的('a', 'b')區(qū)間的第一條記錄,然后把回表后把完整的記錄返給我哈”

InnoDB:“收到,這就去查”,然后InnoDB就通過idx_key1二級索引對應(yīng)的B+樹,快速定位到掃描區(qū)間('a', 'b')的第一條二級索引記錄,然后進行回表,得到完整的聚簇索引記錄返回給server層。

server層收到完整的聚簇索引記錄后,繼續(xù)判斷common_field!='a'條件是否成立,如果不成立則舍棄該記錄,否則將該記錄發(fā)送到客戶端。然后對存儲引擎說:“請把下一條記錄給我哈”

小貼士:

此處將記錄發(fā)送給客戶端其實是發(fā)送到本地的網(wǎng)絡(luò)緩沖區(qū),緩沖區(qū)大小由net_buffer_length控制,默認(rèn)是16KB大小。等緩沖區(qū)滿了才真正發(fā)送網(wǎng)絡(luò)包到客戶端。

InnoDB:“收到,這就去查”。InnoDB根據(jù)記錄的next_record屬性找到idx_key1的('a', 'b')區(qū)間的下一條二級索引記錄,然后進行回表操作,將得到的完整的聚簇索引記錄返回給server層。

小貼士:
不論是聚簇索引記錄還是二級索引記錄,都包含一個稱作next_record的屬性,各個記錄根據(jù)next_record連成了一個鏈表,并且鏈表中的記錄是按照鍵值排序的(對于聚簇索引來說,鍵值指的是主鍵的值,對于二級索引記錄來說,鍵值指的是二級索引列的值)。

server層收到完整的聚簇索引記錄后,繼續(xù)判斷common_field!='a'條件是否成立,如果不成立則舍棄該記錄,否則將該記錄發(fā)送到客戶端。然后對存儲引擎說:“請把下一條記錄給我哈”

... 然后就不停的重復(fù)上述過程。

直到:

也就是直到InnoDB發(fā)現(xiàn)根據(jù)二級索引記錄的next_record獲取到的下一條二級索引記錄不在('a', 'b')區(qū)間中,就跟server層說:“好了,('a', 'b')區(qū)間沒有下一條記錄了”

server層收到InnoDB說的沒有下一條記錄的消息,就結(jié)束查詢。

現(xiàn)在大家就知道了server層和存儲引擎層的基本交互過程了。

那LIMIT是什么鬼?

說出來大家可能有點兒驚訝,MySQL是在server層準(zhǔn)備向客戶端發(fā)送記錄的時候才會去處理LIMIT子句中的內(nèi)容。拿下邊這個語句舉例子:

SELECT * FROM t ORDER BY key1 LIMIT 5000, 1;

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

  • server層向InnoDB要第1條記錄,InnoDB從idx_key1中獲取到第一條二級索引記錄,然后進行回表操作得到完整的聚簇索引記錄,然后返回給server層。server層準(zhǔn)備將其發(fā)送給客戶端,此時發(fā)現(xiàn)還有個LIMIT 5000, 1的要求,意味著符合條件的記錄中的第5001條才可以真正發(fā)送給客戶端,所以在這里先做個統(tǒng)計,我們假設(shè)server層維護了一個稱作limit_count的變量用于統(tǒng)計已經(jīng)跳過了多少條記錄,此時就應(yīng)該將limit_count設(shè)置為1。
  • server層再向InnoDB要下一條記錄,InnoDB再根據(jù)二級索引記錄的next_record屬性找到下一條二級索引記錄,再次進行回表得到完整的聚簇索引記錄返回給server層。server層在將其發(fā)送給客戶端的時候發(fā)現(xiàn)limit_count才是1,所以就放棄發(fā)送到客戶端的操作,將limit_count加1,此時limit_count變?yōu)榱?。
  • ... 重復(fù)上述操作
  • 直到limit_count等于5000的時候,server層才會真正的將InnoDB返回的完整聚簇索引記錄發(fā)送給客戶端。

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

怎么辦?

由于MySQL實現(xiàn)LIMIT子句的局限性,在處理諸如LIMIT 5000, 1這樣的語句時就無法通過使用二級索引來加快查詢速度了么?其實也不是,只要把上述語句改寫成:

SELECT * FROM t, (SELECT id FROM t ORDER BY key1 LIMIT 5000, 1) AS d
    WHERE t.id = d.id;

這樣,SELECT id FROM t ORDER BY key1 LIMIT 5000, 1作為一個子查詢單獨存在,由于該子查詢的查詢列表只有一個id列,MySQL可以通過僅掃描二級索引idx_key1執(zhí)行該子查詢,然后再根據(jù)子查詢中獲得到的主鍵值去表t中進行查找。

這樣就省去了前5000條記錄的回表操作,從而大大提升了查詢效率!

吐個槽

設(shè)計MySQL的大叔啥時候能改改LIMIT子句的這種超笨的實現(xiàn)呢?還得用戶手動想欺騙優(yōu)化器的方案才能提升查詢效率~

到此這篇關(guān)于MySQL中LIMIT語句的文章就介紹到這了,更多相關(guān)MySQL的LIMIT語句內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Unity連接MySQL并讀取表格數(shù)據(jù)的實現(xiàn)代碼

    Unity連接MySQL并讀取表格數(shù)據(jù)的實現(xiàn)代碼

    本文給大家介紹Unity連接MySQL并讀取表格數(shù)據(jù)的實現(xiàn)代碼,實例化的同時調(diào)用MySqlConnection,傳入?yún)?shù),這里的傳入?yún)?shù)個人認(rèn)為是CMD里面的直接輸入了,string格式直接類似手敲到cmd里面,完整代碼參考下本文
    2021-06-06
  • 與MSSQL對比學(xué)習(xí)MYSQL的心得(五)--運算符

    與MSSQL對比學(xué)習(xí)MYSQL的心得(五)--運算符

    MYSQL中的運算符很多,這一節(jié)主要講MYSQL中有的,而SQLSERVER沒有的運算符
    2014-06-06
  • MySQL數(shù)據(jù)庫之字符集?character

    MySQL數(shù)據(jù)庫之字符集?character

    這篇文章主要介紹了MySQL數(shù)據(jù)庫之字符集?character,文章基于MySQL的的相關(guān)資料展開詳細(xì)介紹,具有一定的參考價值需要的小伙伴可以參考一下
    2022-05-05
  • 本機連接虛擬機MYSQL的操作指南

    本機連接虛擬機MYSQL的操作指南

    要讓本機(主機)連接到虛擬機上的 MySQL 數(shù)據(jù)庫,你需要確保虛擬機和主機之間的網(wǎng)絡(luò)連接正常,并且 MySQL 配置允許外部連接,本文給大家介紹了本機連接虛擬機MYSQL的操作指南,需要的朋友可以參考下
    2024-12-12
  • MySQL數(shù)據(jù)庫中遇到no?database?selected問題解決辦法

    MySQL數(shù)據(jù)庫中遇到no?database?selected問題解決辦法

    這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)庫中遇到no?database?selected問題的解決辦法,這是MySQL數(shù)據(jù)庫的錯誤提示,意思是沒有選擇數(shù)據(jù)庫,在使用MySQL命令行操作時需要先選擇要操作的數(shù)據(jù)庫,否則就會出現(xiàn)這個錯誤,需要的朋友可以參考下
    2024-03-03
  • mysql 5.7.30安裝配置方法圖文教程

    mysql 5.7.30安裝配置方法圖文教程

    這篇文章主要為大家分享了mysql 5.7.30安裝配置方法圖文教程,感興趣的小伙伴們可以參考一下
    2016-05-05
  • MySQL 語句注釋方式簡介

    MySQL 語句注釋方式簡介

    這篇文章主要介紹了MySQL 語句注釋方式簡介,方法非常簡單,需要的朋友可以了解下。
    2017-10-10
  • MYSQL導(dǎo)入導(dǎo)出sql文件簡析

    MYSQL導(dǎo)入導(dǎo)出sql文件簡析

    這篇文章主要介紹了MYSQL導(dǎo)入導(dǎo)出.sql文件的相關(guān)資料,內(nèi)容包括MYSQL的命令行模式的設(shè)置、命令行進入MYSQL的方法、數(shù)據(jù)庫導(dǎo)出數(shù)據(jù)庫文件、從外部文件導(dǎo)入數(shù)據(jù)到數(shù)據(jù)庫,感興趣的小伙伴們可以參考一下
    2016-04-04
  • Linux?安裝?MySQL?8.0?及?配置方法

    Linux?安裝?MySQL?8.0?及?配置方法

    本文詳細(xì)介紹了在Ubuntu操作系統(tǒng)上使用MySQL?APT存儲庫安裝和配置MySQL?8.0的步驟,本文通過圖文示例相結(jié)合給大家講解的非常詳細(xì),感興趣的朋友一起看看吧
    2024-11-11
  • MySQL8新特性:自增主鍵的持久化詳解

    MySQL8新特性:自增主鍵的持久化詳解

    MySQL8.0 GA版本發(fā)布了,展現(xiàn)了眾多新特性,下面這篇文章主要給大家介紹了關(guān)于MySQL8新特性:自增主鍵的持久化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07

最新評論

禄丰县| 台北市| 平乐县| 靖西县| 洪江市| 广平县| 衡南县| 阳高县| 南木林县| 理塘县| 扶余县| 夹江县| 左权县| 开化县| 望城县| 钟祥市| 明光市| 新密市| 龙山县| 万安县| 鄢陵县| 东阿县| 济源市| 柳州市| 花莲县| 旌德县| 全南县| 蒙阴县| 万安县| 桐乡市| 平陆县| 集安市| 秦安县| 天全县| 九龙坡区| 宝兴县| 巴彦淖尔市| 平南县| 宁化县| 吴江市| 甘肃省|