註:以下所有內容均為自己總結的筆記,涉及底層原理,難度對標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。
一般有兩個好處:
- 在分散式環境下保證唯一性,因為夠長且重覆概率太低,否則,A模塊的id=1,可能會與B模塊的id=1混淆。
- 黑客不容易猜到相鄰的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值時就直接中斷。