MySQL索引底層原理相關問題自總結(難度對標18K-25K薪資,已總結80+,持續更新中)

来源:https://www.cnblogs.com/phpphp/p/18062304
-Advertisement-
Play Games

註:以下所有內容均為自己總結的筆記,涉及底層原理,難度對標18K-25K薪資,偏理論,不保證百分百準確性。 索引查找快速的原理? 創建索引的本質是排序,排好序之後再找數據就快了。 對於B+tree索引,B+tree對數據排序後採用多路查找思想的非線性查找方案,減少了大量的查詢次數,從而避免多次磁碟i ...


註:以下所有內容均為自己總結的筆記,涉及底層原理,難度對標18K-25K薪資,偏理論,不保證百分百準確性。

索引查找快速的原理?

創建索引的本質是排序,排好序之後再找數據就快了。
對於B+tree索引,B+tree對數據排序後採用多路查找思想的非線性查找方案,減少了大量的查詢次數,從而避免多次磁碟io,進而快速找到結果。

為什麼推薦用自增id做主鍵?

自增id直觀,且不用刻意維護這個欄位,減少工作量,還能避免主鍵更新引起的頁分裂。
舉例說明頁分裂:數據是存在頁上的,頁1存儲id為1、2、5的數據,如果沒有設置自增,如果突然新增了id為3、4的數據,頁1無剩餘空間存儲,就需要將頁1數據進行拆分,頁1存儲id為1、2、3的數據,頁2存儲id為4、5的數據,分裂的目的是為了排序,排序的目的是為了方便查找。分裂需要消耗計算資源用於更改數據,這種非必要發生的操作就儘量避免。

什麼是鏈表 ,在索引中起到了什麼作用?

鏈表是一種線性數據結構,由節點組成,每個節點包含兩部分:數據和指向相鄰節點的指針。
鏈表分單向和雙向。
單向:節點只有一個指針,指向下一個節點
雙向:每個節點有兩個指針,一個指向前一個節點,一個指向後一個節點。
根據對鏈表的操作,又可以分為隊列和棧。
隊列:先進先出(LPush->RPop,或Ppush->Rpop)。
棧:先進後出(LPush->LPop,或RPush->RPop)。

MySQL InnoDB引擎和MyISAM引擎,都用的B+tree演算法作索引,在葉子節點,每個節點間使用向左或者向右的指針,來移動指針,這也是索引支持區間查詢的原因,葉子節點間組成一個鏈表。

什麼是B+tree?

是一種通過排序,方便查找的數據結構,特別是在資料庫和文件系統的實現中廣泛應用。它是一種平衡樹的變體。
平衡性: 所有葉子節點都位於同一層,使得在樹的高度方面達到平衡,從而保持高效的查找、插入和刪除操作。
有序性: B+樹的葉子節點按照鍵值大小順序存儲,使得範圍查詢變得更為高效。
多路搜索: 每個非葉子節點都有多個子節點,允許更多的分支,提高搜索效率。
適用於範圍查詢: 由於有序性和多路搜索的特性,B+樹在範圍查詢方面表現優秀。
在資料庫系統中,B+樹常被用作索引結構,用於加速對資料庫表的查詢操作。其設計考慮了磁碟存儲的特性,使得在磁碟上的讀寫操作更為高效。

B+tree比二叉樹好在那裡?

更加平衡:二叉樹在遇到一組非混亂的數據集合下,樹的層級會變的很高,意味著io的次數變多,B+tree避開了這個問題。
多路搜索:二叉樹為雙路搜索,B+tree為多路搜索,極大提高了搜索效率。
查找方便:無論是區間查找還是定值查找,B+tree都比二叉樹查找方便,二叉樹需要中序遍歷才能得到有序序列。

Btree與B+tree區別?

Btree:非葉子節點存放數據,葉子節點無指針,支持區間查找。
B+tree:非葉子結點不存放數據,葉子節點有指針,支持更快速的區間查找。
正因為Btree非葉子節點存放數據,查詢起來無法像B+tree一樣葉子節點間依靠鏈表進行範圍查詢,所以區間查詢效率低。
Btree做查找,需要在葉子節點和非葉子節點之間來回跳躍搜索,來回的跳躍,意味著需要更多的磁碟io,而B+tree只需要從非葉子節點到葉子節點即可,
所以穩定性不如B+tree。

為什麼MySQL採用B+tree?

查詢高效:因為B+tree採用多路非線性查找思想,降低樹的層級,減少磁碟io。
支持區間查詢:因為數據全在葉子節點上,每個節點之間有指針做關聯。
演算法穩定:不會向二叉搜索樹那樣,層級和數據有關,查找情況時好時壞。

頁根頁之間怎麼關聯?

雙向鏈表。
雙向鏈表因為有序,所以可以適用二分查找。
雙向鏈表,鏈的是行中存儲的元數據,這歸行格式管理,行格式存儲的其中一項叫做record_type,有4個值,0表示普通用戶記錄,1表示目錄項紀錄,2表示當前頁的最小值,3表示當前頁的最大值。
使用0和1區分是目錄頁還是數據頁。使用2和3走索引時用於定位,進行區間或等值查找。

為什麼數據在頁上,頁本身要加索引?

雖然一個頁可以存儲多條數據,但是在大數據情況下,一個頁不夠存就需要多個頁,為了避免查找數據時數據不用對大量的頁挨個遍歷。與是也加上了B+tree用於查找。

B+tree 葉子節點之間怎麼關聯

雙向的指針。

什麼是聚簇索引?

在InnoDB引擎中,索引的葉子節點存儲的是實際的數據行,數據即索引,索引即數據。
好處就是能帶來快速的查詢速度,通過索引就可以找到實實在在的數據。
一般一個表只能有一個聚簇索引,一般為主鍵,因為數據的排列就是按照索引來的,如果一個表中有多個聚簇索引,一是不知道二級索引參考哪個,二是太占空間。

MyISAM有聚簇索引嗎?

沒有。
查看MyISAM的二進位文件,有.MYI(存儲索引)和.MYD(存儲數據)尾碼結尾的文件,他們的索引和數據是分開的,不符合數據即索引,索引即數據的特點。
MyISAM的葉子結點存儲的是數據的位置信息。

MyISAM中B+tree的葉子節點存儲的是數據的地址,也需要類似回表的操作,為什麼性能也不慢?

因為定址的性能也挺高的,如果速度慢,就不會這麼主流了。

為什麼InnoDB比MyISAM有更好的併發性能,是因為索引上有什麼不同之處嗎?

不是,併發性和不同引擎的索引沒有太多相關性。
InnoDB有更好的併發性能,是因為它支持粒度更小的行級鎖,併發情況下,事務用於保持數據一致性,鎖是併發控制必備的機制。

為什麼InnoDB不推薦用較長的數據做主鍵?

大數據情況下,InnoDB引擎創建的二級B+tree索引,葉子節點是主鍵,較長的主鍵,會占用更多的位置。
而MyISAM中B+tree的葉子節點,存儲的是數據的位置。

如何區分一棵B+tree是不是聚簇索引?

看這顆樹的葉子節點上,存儲的是實實在在的數據,還是根據當前列關聯的主鍵。

聚簇索引的優點?

把實實在在的數據當索引,不用回表,性能很高,因為通過索引找到的那條數據,就是所在行的數據。
InnoDB引擎,MySQL 預設情況下使用自增主鍵作為聚簇索引,這便是主鍵查詢快的原因。

聚簇索引的缺點?

如果插入的數據不是自增的數字id,可能引起索引分裂,降低性能。
占用較大的空間。

為什麼主鍵查詢性能很高?

InnoDB引擎,MySQL 預設情況下使用自增主鍵作為聚簇索引,不用回表。這便是主鍵查詢快的原因。
具有唯一索引,定值查找,查到後不必接著找。

為什麼不建議用UUID作為主鍵?

避免索引分裂,影響插入數據時的性能問題。
必須要明白,索引的本質是排序,索引查找的本質是根據排好序的數據進行查找。
可能後生成的uuid,根據ASCII碼字典排序,會排到先生成uuid的前面,插入新值,則需要重新排序,就要破壞掉原本的索引結構,這個過程將消耗時間和算力。

c3dc38e1-8db2-4e9f-9fe4-735e88facdb4,像是這種類型的數據叫做uuid。
一般有兩個好處:

  1. 在分散式環境下保證唯一性,因為夠長且重覆概率太低,否則,A模塊的id=1,可能會與B模塊的id=1混淆。
  2. 黑客不容易猜到相鄰的uuid是什麼,就算程式有越權漏洞,也不會很難根據原ID猜測其它ID。

其次是uuid,占用空間比int類型更大,使得其它二級索引,存儲主鍵時,占用更多的空間。

用自增id就不會出現索引分裂的情況嗎?

不是的。
自增的有序id,只會減少插入數據時的分裂,當大數據時的新增引起的B+tree分層,或者對數據的的插入和刪除操作,都可能為了局部重建索引,觸發分裂操作。

什麼是非聚簇索引?

非聚簇索引則將索引與實際數據行分開存儲,索引的葉子節點存儲的是當前索引值與主鍵(MyISAM則是當前索引值與行地址),不是所在行的數據。

什麼是二級索引?

級索引通常指的是除了表的主鍵之外創建的額外索引。

什麼是輔助索引?

一般是指非聚簇索引或者二級索引。

什麼是回表?

InnoDB引擎,在非聚簇的B+tree索引上,樹的葉子節點存儲的是當前索引欄位數據和主鍵的值,當前的葉子節點數據與主鍵做邏輯上的關聯,而不是存儲所在行的全部數據,所以需要根據主鍵,再次查詢一遍數據,這個過程叫回表。
因內部多了一輪的查詢流程,所以性能有所降低,所以能用主鍵查詢的場景,就不要使用其它欄位。

為什麼不通過像聚簇索引一樣的方式避免回表?

技術上能實現,但是缺點很明顯,空間換時間的代價太大。
在非聚簇的B+tree上,樹的葉子節點重覆存儲所在行的值,會造成大量的空間浪費。
其次是更新代價太大,可能更新一小塊數據,就需要對這些索引上的數據做同步更新。
所以做邏輯關聯更好。

為什麼插入、更新、刪除數據時,非聚簇索引比聚簇索引性能略高?

插入數據引起的索引分裂問題,非聚簇索引只需要調整當前索引的位置和主鍵就好,而非聚簇所以需要移動整行的數據。

什麼是聯合索引?

組合索引、複合索引、多列索引,聯合索引一個意思,多個欄位組合去創建索引。
索引排序規則:先按照左邊的欄位進行排序,如果左邊欄位相同,再根據右邊的欄位排序。

什麼是首碼索引?

MySQL 首碼索引是一種,它只對列值的前部進行索引,而不是對整個列值進行索引。
做法:alter table 表名 add index (filed_name(長度));
優點:主要用於控制索引大小,由於底層在比較時字元串長度較短,所以比較起來也比單列索引塊。
缺點:有誤差,所以需要在空間和產品服務方面做取捨。
評估設置長度:需要根據數據情況測試,如果count(distince left('欄位名', 10)) / count(*) 等於1左右,說明截取欄位前10個字元去重後的數量,等於總數,說明依照前10個字元就能辨識度很高。如果結果略小於1,說明辨識度還不夠,可以取12,如果遠小於1,長度取20再試試,以此類推。
補充:《阿裡巴巴Java開發手冊》【強制】在varchar簡歷索引時,必須指定索引長度,沒必要對全欄位建立索引,根據實際文本區分度決定索引長度。

聯合索引算不算聚簇索引?

相似但不算,聯合索引關聯的不是所在行的全部欄位,而是部分欄位。

為什麼單表數據不能超過2000萬條

這是個粗略的理論值,很多人說超過這個數,會把B+tree的層級轉為4層,其實不准的。
這個還是要看葉子節點數據的大小,如果葉子結點很大,需要更多的頁,則存不了太多,如果葉子節點數據很少,有人推算,存1個億也沒問題的。

先排除一些元數據的存儲:數據存儲在頁上,每頁大小16KB,每頁需要開闢一些新的空間來存儲元數據(例如指向上一頁下一頁的指針),頁頭存儲文件頭38位元組,頁面頭56位元組,最小記錄和最大記錄26個位元組,為了保證不出錯,出現了校驗和的機制,這塊功能的存儲被放到了頁尾,占8個位元組。頁里的數據呢,為了方便查找每行的數據,所以包含頁目錄(採用二分法,把查詢複雜度從O(n)優化為O(log n)),這也占空間,這些可以粗略的估計為占用了1KB。

聲明代數:假設非葉子節點指向葉子節點的指針數量為X,葉子節點能夠容納的行數為Y,B+tree層數為Z,那麼能存儲的總行數就是Xz-1 * Y。

計算X:主鍵假設用bigint,占8個位元組,頁號這個元數據占4個位元組,非葉子節點一條數據占12個位元組,15KB / 12B = 1280。
計算Y:假設一個行數據為1KB,也就是說可以放15條數據。

若Z為1:12800 * 15 = 15行
若Z為2:12801 * 15 = 19200行
若Z為3:12802 * 15 = 24576000行
若Z為3:12803 * 15 = 31457280000行

但是這是理想情況,很多主鍵id都用無符號int,能節省4個位元組,行數大小也不確定,所以這是個理論值,究竟是多少,需要根據實際情況討論。

什麼是最左匹配原則?

生效的情況:
abc創建聯合索引,where a = 'v1' and b = 'v2' and c= 'v3',where順序可以顛倒,但是必須都是and,左邊的列不能包含區間查詢。
失效的情況:
多欄位創建聯合索引,如果聯合索引左邊的欄位的查詢條件不存在,或者聯合索引左邊欄位使用的區間查詢,或者使用了or,都會導致索引失效。
註意,這裡說的順序,是聯合索引的順序,不是where條件的順序。

底層什麼原因導致最左匹配原則?

B+tree聯合索引排序,是根據ASCII碼的字典順序進行從左到右依字元排序,然後依欄位從左到右排序,沒有其它方向的排序,這就不能相容更多種的查詢方式。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3,此時欄位索引的使用情況?

每個欄位都能用上索引。

假如abc三個欄位創建聯合索引,where a = v1 or b = v2 or c = v3,此時欄位索引的使用情況?

a能用上索引,b和c都無法使用索引,因為and是屬於流水線式的篩選,而or是與前面的搜索條件不相關的個體,b和c都沒有左邊的欄位配合成為聯合索引。

假如abc三個欄位創建聯合索引,where a = v1 and b > v2 and c = v3,此時欄位索引的使用情況?

a能用上索引,b能用上索引,c無法使用上索引,因為b是區間查詢導致c無法按索引查詢。

假如abc三個欄位創建聯合索引,where a = v1 and c = v3,此時欄位索引的使用情況?

a可以用上索引,c用不上索引,因為缺少b。

假如abc三個欄位創建聯合索引,where b = v1 and c = v3,此時欄位索引的使用情況?

b和c都用不上索引,因為缺少a。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3 or c is null,此時欄位索引的使用情況?

abc三個欄位全部能用上索引。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3 or d + 1 = 10,此時欄位索引的使用情況?

用explain實測,type為all,索引用不上了,全表查,因為使用了表達式。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3 and d + 1 = 10,此時欄位索引的使用情況?

用explain實測,type為ref,並根據key_len欄位評估,abc都能使用索引。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3 and length(d) < 20,此時欄位索引的使用情況?

用explain實測,type為ref,並根據key_len欄位評估,abc都能使用索引。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3 or length(d) < 20,此時欄位索引的使用情況?

用explain實測,type為all,索引用不上了,全表查,因為使用了函數。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3 or c = v4,此時欄位索引的使用情況?

用explain實測,type為all,索引用不上了,全表查,因為c列沒有建索引。

假如abc三個欄位創建聯合索引,where a = v1 and b = v2 and c = v3 and c = v4,此時欄位索引的使用情況?

用explain實測,type為ref,並根據key_len欄位評估,abc都能使用索引。

假如abc三個欄位創建聯合索引,where a > v1 and b = v2 and c = v3,索引失效,explain type為all,數據量大還經常查詢,怎麼辦?

創建bca的聯合索引即可,alter table 表名 add index(b,c,a),每個欄位,最好加上索引長度。
abc的聯合索引,如果用不上,刪掉。alter table 表名 drop index 索引名。

為什麼不推薦mysql頻繁使用null值?

null值是個特殊的存在,在sql查詢上,即使是唯一索引列,也允許插入多個null值,這影響了了唯一索引的唯一性約束。
其次有些查詢,用where field = '',或者where filed = null,都是匹配補上的,只能用is null。
null值影響聚合函數的使用,導致count(欄位)結果不符合真實情況。
否則就難以區分到底是沒有關聯記錄還是其他情況。

什麼是索引下推?

索引下推簡稱ICP,優化SQL執行的一種策略,將where條件下推至存儲引擎執行,減少回表的數據量提高性能。
一般是針對二級索引說的,有多個where條件時,執行完第一個條件不著急回表,用剩餘的數據再次執行第二個where條件,減少回表的數據量。
索引下推常見在聯合索引中,只有使用了聯合索引中的欄位的時候,才可以。
舉例:百萬條數據,第一次where之後剩下1000條,執行完第二次where後身下5條,只需要回表5條數據即可,避免第一次where條件剩下的1000條數據回表,然後在執行第二個where,再回表。

為什麼有覆蓋索引時,不支持索引下推?

使用了覆蓋索引,說明索引的數據滿足了當前select查詢,不需要回表,已經不需要下推了。
索引下推有個暗含的前提,是索引無法完全滿足當前查詢前提的優化策略,且where的欄位又包含在聯合索引中,索引下推的終極目的是減少回表數據數量,既然不需要回表,那就不需要下推。

為什麼相關子查詢,不支持索引下推?

相關子查詢,指的是子sql與父sql的參數動態關聯,這會導致子SQL語句的參數處於動態(不確定)狀態,導致索引下推的目標都無法確定,所以不行。

什麼是mysql filesort?

這是mysql explain中Extra中可能會展示的東西,當然也是一種機制,在order by的場景中去用。
這種方式指的是在記憶體中排序,效率略低,因為沒有按照索引排序,儘量避免。
與之相對的,有個index排序,可以按照索引自然而然的排序,效率偏高。

filesort兩種排序演算法是什麼?

雙路排序:相對較慢。先找到orderby的列,然後排序,再根據排序的欄位查找其它欄位,類似回表,所以慢。其次相對於單路排序更可能發生隨機io,order by排序後的數據,可能不在同一個頁上,這個過程需要來回的讀取頁中的數據。
單路排序:相對較快,根據orderby的列,一次性取出來所有欄位,然後再排序。

什麼是覆蓋索引?

要查詢的欄位上有索引,索引中的欄位涵蓋了select欄位的結果,因為不需要回表操作去查詢整行數據,避免回表的隨機io(回表的數據可能不在同一個頁上),這是一種性能優化的提現。
需要儘可能少select 欄位的數量,避免使用select *。

什麼情況下not in、is not null、<>、!=,左%能用上索引?

覆蓋索引。
要查詢的欄位上有索引,不用回表,卸掉了一個重擔,MySQL優化器認為這代價不大,所以選擇用索引。
這種情況下,explain type為index。

什麼是Hash索引?

基於哈希表實現的索引結構,用於快速定位數據的存儲位置。在Hash索引中,索引鍵通過哈希演算法計算得到一個哈希值,該哈希值指向存儲數據的具體位置,從而實現快速的查找和定位。

MyISAM和InnoDB都支持哈希索引嗎?

都不支持,只有Memory引擎支持。
並且不支持區間查找,所以索引主要依靠B+tree。

where條件的順序會影響使用索引嗎?

如果都是and,則不影響。
MySQL有個東西叫做優化器,它會根據查詢的欄位,篩選的欄位,索引情況自動調整。
order by調整順序會影響結果。

where條件左邊的or遇見右邊的and,誰會先執行?

or的優先順序比and更小,會先執行右邊的and,再執行左邊的or,所以要控制好。避免索引失效。

那些查詢適合創建索引?

  • 需要唯一性約束兜底的欄位。
  • 經常被查詢或者作為where條件的欄位,=、>、<、<=、>=、in、between、like 右百分號
  • 經常group by或者order by的欄位。
  • delete或update被作為where條件的欄位。
  • distinct的欄位。
  • join on的連接欄位需要加索引,但是需要類型一致,因為MySQL內部有用函數做隱式轉換,用了函數就不適用索引。
  • 區分度(不重覆度)高的欄位。
  • 把搜索最頻繁的列,放在聯合索引的左側,(受聯合索引的最左原則影響)。

那些查詢不適合創建索引?

  • 數據量小,一個表,例如配置表,總類別表,可能最多幾十條記錄,創建不創建區別不大。
  • 寫多讀少,數據的寫操作對索引欄位的開銷比沒有索引要大,而且讀操作還少。
  • 區分度低的欄位,例如性別狀態等,這會導致線性查找,能提升搜索效率,但是不明顯,可加可不加。
  • sql語句包含<>、!=、not in、is not null,無法使用索引,所以專門用作排除性查找的,不建議創建索引。

哪些情況下索引會失效?

  • 使用not in、is not null、<>、!=、這種排除法時會導致索引失效,覆蓋索引除外。
  • 最左匹配原則,左邊的欄位缺少時會出現,覆蓋索引除外。
  • 最左匹配原則,左邊的欄位有區間查詢,導致右邊的欄位無法使用索引。
  • like左邊或兩邊加百分號。
  • 類型的隱式轉換,如varchar的欄位,使用where varchar_field = 123,包括join表,用on連接的欄位。
  • where條件有函數,或表達式。
  • where語句包含or,or中存在非索引列。
  • 大數據量對二級索引欄位排序,如果select * 或者其它欄位,這個過程涉及回表,可能無法使用索引,因為數據量大,走索引的每條數據都需要回表,代價會很大。
  • order by欄位,如果排序與索引順序不一致,則可能導致索引失效,如果order by的每個欄位,都按照索引的順序,或者反順序,則仍舊會走索引。

如果一個表中的每個欄位都加了單列索引,且每個欄位都查詢條件的操作,哪個索引會被優先使用?

這是個開放性的問題,不能一概而論,不過可根據SQL語句的執行順序判斷,先執行sql語句的某個部分,如果這個部分有索引,那就使用這個索引,其它索引在此查詢過程中用不上。
可使用explain參考。

B+tree和Hash索引的適用場景?

B+tree:等值查找,區間查找,批量等值查找,order by。
hash:等值查找。

為什麼大數據情況下,使用select *,並對某個或某些二級索引列order by,會導致索引失效?

因為數據量大又使用select * ,會導致二級索引的排序需要回表,這個太耗資源。所以MySQL優化器選擇了全表查。
親測加一個limit數據量不超過49000,就能解決這個問題,explain type由all變成了index。

為什麼唯一索引比普通索引略快 ?

唯一索引找到數據就不往下找了。

一次查詢,表中多個索引都可用,MySQL優化器只能選一個嗎?

多數情況下是,但是還有index_merge(explain type的值)的情況。使用了多個單列索引來執行查詢。當在查詢條件中存在多個列,且每個列都有單獨的索引時。

什麼是自適應哈希?

InnoDB不支持hash索引,但是提供了一個自適應的哈希索引,屬於MySQL內部的優化機制。
某些數據被經常訪問,滿足等值查詢的時候,就會將這個數據頁的地址存放到哈希表中,下次查詢的時候直接用。
MySQL5.7和8預設都是開啟的狀態,可使用select @@innodb_adaptive_hash_index來查看。

為什麼很多人都在講索引就不得不提磁碟io?

因為最耗時的環節就在磁碟io上,索引就是為了減少磁碟io的次數。

欄位被刪除時,索引的情況?

單列索引,欄位被刪除時,同步刪除索引。
聯合索引,部分欄位被刪除時,索引刪除,自動根據剩餘欄位重建索引。索引全部欄位被刪除時,索引刪除。

什麼是降序索引?

這是mysql8的新特性,創建索引時指定索引的排序方式為降序,CREATE INDEX idx_column_name ON table_name (column_name DESC);
對創建聯合索引的列,進行不同的排序順序時,使用降序排序,會提高性能。
前提是,需要保證創建索引的升降序與排序的升降序一致。

為什麼子查詢比join慢?

子查詢的過程創建了臨時表,臨時表的創建和銷毀會占用時間。
而join的過程,會產生一個結果集,這個結果集不是臨時表。

count(*)、count(1)、count(欄位),count(id)怎麼選,哪個性能高?

如果想統計全部數據,不推薦用count(欄位),因為遇到null值不會+1,如果統計某欄位數量,用count(欄位)。
性能方面,同一個引擎下差不多。
不同引擎下,MyISAM比InnoDB引擎性能高,MyISAM中,表的元數據就存了count值,通過表級鎖自動維護一致性。時間複雜度為O(1)。InnoDB採用行級鎖和MVCC機制(事務相關分為當前讀和快照讀之分,不同的事務隔離級別和讀出的數據不一致,會造成不准確的情況),無法採用MyISAM的方案,所以要全表掃描,時間複雜度O(n)。

sql執行順序where優先於limit,在不加索引的列使用where,為什麼大數據情況下加limit 1能顯著提升性能?

sql的執行順序是:form->join on->where->group by->having->select->order by->limit,確實where在limit前面。
但是MySQL Server有個查詢優化器的東西,大概是預載入了limit,在where環節找到數據後立馬停止。
本問題沒有找到官方說明,只是個人推斷。
推斷過程如下:
隨便找了一個省市區縣鎮的四級聯動的表,共46462條數據,name欄位為中文,無索引,所以該欄位where是全表掃描。
把全表數據複製了32遍,共1486784條數據,執行select * from address where name like '%北京%',不加limit 1用時11.62秒,加上limit 1用時0.04秒,性能提升幾百倍,如果limit在where全部取篩選數據後在截取,指望著限制條目,性能就提升幾百倍,幾乎不可能。因為最耗時過程是where環節的全表掃描,所以才猜測是預載入了limit,在where查詢數據數量符合limit值時就直接中斷。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • proxy_set_header 是 Nginx 配置中的一個重要指令,特別是在使用 Nginx 作為反向代理時。該指令允許你修改由 Nginx 傳遞給代理後端的請求頭。這對於確保後端應用程式能夠接收到正確的客戶端信息(如 IP 地址、主機名等)以及控制緩存行為等場景非常有用。 以下是 proxy_ ...
  • 集群部署方案(2 Master + 3 Worker) Apache DolphinScheduler官網:https://dolphinscheduler.apache.org/zh-cn Apache DolphinScheduler使用文檔:https://dolphinscheduler.a ...
  • 本文分享自華為雲社區《GaussDB(DWS) 集群通信系列一:pooler連接池》,作者:半島里有個小鐵盒。 1.前言 適用版本:【8.1.0(及以上)】 GaussDB(DWS) 為MPP型分散式資料庫,使用Share Nothing架構,數據分散存儲在各個DN節點,而CN不存儲數據,作為接收查 ...
  • 某業務系統將MySQL 8.0.26升級為GreatSQL 8.0.32-24 後,某些特定的SQL語句不能查詢到數據。經測試 MySQL 8.0.32也存在相同的問題 此BUG已在 GreatSQL 8.0.32-25 版本中解決 MySQL 8.0.26版本升級32版本查詢數據為空的跟蹤 接到客 ...
  • 查詢 語法: SELECT 標識選擇哪些列 FROM 標識從哪個表中選擇 去重(Distinct) 在SELECT語句中使用關鍵字DISTINCT去除重覆行 SELECT DISTINCT department_id FROM employees; 過濾(Where) 語法: SELECT 欄位1, ...
  • 本文說明的是MySQL鎖,和操作系統或者編程語言的鎖無關。 概念 作用:在併發情況下讓數據正確的讀寫。 優點:併發情況下對數據讀寫可控,防止出錯。 缺點:降低性能、增加難度。 分類 數據操作類型劃分 讀鎖(共用鎖、S鎖) 寫鎖(排它鎖、獨占鎖、X鎖) 粒度劃分 表級鎖 S鎖、X鎖 意向鎖 自增鎖 元 ...
  • 聲明測試表,供文章案例使用 CREATE TABLE `cs` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `num` int(10) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoD ...
  • Slow Log 簡介 用於記錄執行時間超過指定值的 SQL 語句的詳細信息,多用於調試和監控。 配置 因為開啟會略微影響性能,所以預設沒有開啟,所以需要配置。 查看是否開啟 show variables like '%slow%'; + + + | Variable_name | Value | ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...