您好,登錄后才能下訂單哦!
本篇內容主要講解“mysql的索引技巧有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“mysql的索引技巧有哪些”吧!
MySQL的存儲引擎架構將查詢處理與數據的存儲/提取相分離。下面是MySQL的邏輯架構圖:
每個客戶端的連接都對應著服務器上的一個線程。服務器上維護了一個線程池,避免為每個連接都創建銷毀一個線程。當客戶端連接到MySQL服務器時,服務器對其進行認證。可以通過用戶名和密碼的方式進行認證,也可以通過SSL證書進行認證。登錄認證通過后,服務器還會驗證該客戶端是否有執行某個查詢的權限。
編譯SQL,并對其進行優化(如調整表的讀取順序,選擇合適的索引等)。對于SELECT語句,在解析查詢前,服務器會先檢查查詢緩存,如果能在其中找到對應的查詢結果,則無需再進行查詢解析、優化等過程,直接返回查詢結果。存儲過程、觸發器、視圖等都在這一層實現。
存儲引擎負責在MySQL中存儲數據、提取數據、開啟一個事務等等。存儲引擎通過API與上層進行通信,這些API屏蔽了不同存儲引擎之間的差異,使得這些差異對上層查詢過程透明。存儲引擎不會去解析SQL。
MyISAM:每個MyISAM在磁盤上存儲成三個文件。分別為:表定義文件、數據文件、索引文件。第一個文件的名字以表的名字開始,擴展名指出文件類型。.frm文件存儲表定義。數據文件的擴展名為.MYD (MYData)。索引文件的擴展名是.MYI (MYIndex)。
InnoDB:所有的表都保存在同一個數據文件中(也可能是多個文件,或者是獨立的表空間文件),InnoDB表的大小只受限于操作系統文件的大小,一般為2GB。
MyISAM: MyISAM支持支持三種不同的存儲格式:靜態表(默認,但是注意數據末尾不能有空格,會被去掉)、動態表、壓縮表。當表在創建之后并導入數據之后,不會再進行修改操作,可以使用壓縮表,極大的減少磁盤的空間占用。
InnoDB: 需要更多的內存和存儲,它會在主內存中建立其專用的緩沖池用于高速緩沖數據和索引。
MyISAM:數據是以文件的形式存儲,所以在跨平臺的數據轉移中會很方便。在備份和恢復時可單獨針對某個表進行操作。
InnoDB:免費的方案可以是拷貝數據文件、備份 binlog,或者用 mysqldump,在數據量達到幾十G的時候就相對痛苦了。
MyISAM:強調的是性能,每次查詢具有原子性,其執行數度比InnoDB類型更快,但是不提供事務支持。
InnoDB:提供事務支持事務,外部鍵等高級數據庫功能。 具有事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。
MyISAM:可以和其他字段一起建立聯合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,他可以根據前面幾列進行排序后遞增。
InnoDB:InnoDB中必須包含只有該字段的索引。引擎的自動增長列必須是索引,如果是組合索引也必須是組合索引的第一列。
MyISAM: 只支持表級鎖,用戶在操作myisam表時,select,update,delete,insert語句都會給表自動加鎖,如果加鎖以后的表滿足insert并發的情況下,可以在表的尾部插入新的數據。
InnoDB: 支持事務和行級鎖,是innodb的最大特色。行鎖大幅度提高了多用戶并發操作的新能。但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。
MyISAM:支持 FULLTEXT類型的全文索引
InnoDB:不支持FULLTEXT類型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。
MyISAM:允許沒有任何索引和主鍵的表存在,索引都是保存行的地址。
InnoDB:如果沒有設定主鍵或者非空唯一索引,就會自動生成一個6字節的主鍵(用戶不可見),數據是主索引的一部分,附加索引保存的是主索引的值。
MyISAM: 保存有表的總行數,如果select count() from table;會直接取出出該值。
InnoDB: 沒有保存表的總行數,如果使用select count(*) from table;就會遍歷整個表,消耗相當大,但是在加了wehre條件后,myisam和innodb處理的方式都一樣。
MyISAM:如果執行大量的SELECT,MyISAM是更好的選擇。
InnoDB:如果你的數據執行大量的INSERT或UPDATE,出于性能方面的考慮,應該使用InnoDB表。
MyISAM:不支持
InnoDB:支持
性能低、執行時間太長、等待時間太長、連接查詢、索引失效。
(1)編寫過程
select distinct ... from ... join ... on ... where ... group by ... having ... order by ... limit ...
(2)解析過程
from ... on ... join ... where ... group by ... having ... select distinct ... order by ... limit ...
索引相當于書的目錄。
索引的數據結構是B+樹。
(1)提高查詢效率(降低IO使用率)
(2)降低CPU使用率
比如查詢order by age desc,因為B+索引樹本身就是排好序的,所以再查詢如果觸發索引,就不用再重新查詢了。
(1)索引本身很大,可以存放在內存或硬盤上,通常存儲在硬盤上。
(2)索引不是所有情況都使用,比如①少量數據②頻繁變化的字段③很少使用的字段
(3)索引會降低增刪改的效率
(1)單值索引
(2)唯一索引
(3)聯合索引
(4)主鍵索引
備注:唯一索引和主鍵索引唯一的區別:主鍵索引不能為null
alter table user add INDEX `user_index_username_password` (`username`,`password`)
MySQL索引的底層數據結構是B+樹
B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索引結構。
B-Tree結構圖中每個節點中不僅包含數據的key值,還有data值。而每一個頁的存儲空間是有限的,如果data數據較大時將會導致每個節點(即一個頁)能存儲的key的數量很小,當存儲的數據量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁盤I/O次數,進而影響查詢效率。在B+Tree中,所有數據記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只存儲key值信息,這樣可以大大加大每個節點存儲的key值數量,降低B+Tree的高度。
B+Tree相對于B-Tree有幾點不同:
非葉子節點只存儲鍵值信息。
所有葉子節點之間都有一個鏈指針。
數據記錄都存放在葉子節點中。
將上一節中的B-Tree優化,由于B+Tree的非葉子節點只存儲鍵值信息,假設每個磁盤塊能存儲4個鍵值及指針信息,則變成B+Tree后其結構如下圖所示:
通常在B+Tree上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即數據節點)之間是一種鏈式環結構。因此可以對B+Tree進行兩種查找運算:一種是對于主鍵的范圍查找和分頁查找,另一種是從根節點開始,進行隨機查找。
可能上面例子中只有22條數據記錄,看不出B+Tree的優點,下面做一個推算:
InnoDB存儲引擎中頁的大小為16KB,一般表的主鍵類型為INT(占用4個字節)或BIGINT(占用8個字節),指針類型也一般為4或8個字節,也就是說一個頁(B+Tree中的一個節點)中大概存儲16KB/(8B+8B)=1K個鍵值(因為是估值,為方便計算,這里的K取值為〖10〗^3)。也就是說一個深度為3的B+Tree索引可以維護10^3 * 10^3 * 10^3 = 10億 條記錄。
實際情況中每個節點可能不能填充滿,因此在數據庫中,B+Tree的高度一般都在2~4層。MySQL的InnoDB存儲引擎在設計時是將根節點常駐內存的,也就是說查找某一鍵值的行記錄時最多只需要1~3次磁盤I/O操作。
數據庫中的B+Tree索引可以分為聚集索引(clustered index)和輔助索引(secondary index)。上面的B+Tree示例圖在數據庫中的實現即為聚集索引,聚集索引的B+Tree中的葉子節點存放的是整張表的行記錄數據。輔助索引與聚集索引的區別在于輔助索引的葉子節點并不包含行記錄的全部數據,而是存儲相應行數據的聚集索引鍵,即主鍵。當通過輔助索引來查詢數據時,InnoDB存儲引擎會遍歷輔助索引找到主鍵,然后再通過主鍵在聚集索引中找到完整的行記錄數據。
(1)使用聯合索引的全部索引鍵可觸發聯合索引
(2)使用聯合索引的全部索引鍵,但是用or連接的,不可觸發聯合索引
(3)單獨使用聯合索引的左邊第一個字段時,可觸發聯合索引
(4)單獨使用聯合索引的其它字段時,不可觸發聯合索引
explain可以模擬sql優化執行sql語句。
(1)用戶表
(2)部門表
(3)未觸發索引
(4)觸發索引
(5)結果分析
explain中第一行出現的表是驅動表。
指定了聯接條件時,滿足查詢條件的記錄行數少的表為[驅動表]
未指定聯接條件時,行數少的表為[驅動表]
對驅動表直接進行排序就會觸發索引,對非驅動表進行排序不會觸發索引。
(1)id:SELECT識別符。這是SELECT的查詢序列號。
(2)select_type:SELECT類型:
SIMPLE: 簡單SELECT(不使用UNION或子查詢)
PRIMARY: 最外面的SELECT
UNION:UNION中的第二個或后面的SELECT語句
DEPENDENT UNION:UNION中的第二個或后面的SELECT語句,取決于外面的查詢
UNION RESULT:UNION的結果
SUBQUERY:子查詢中的第一個SELECT
DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決于外面的查詢
DERIVED:導出表的SELECT(FROM子句的子查詢)
(3)table:表名
(4)type:聯接類型
system:表僅有一行(=系統表)。這是const聯接類型的一個特例。
const:表最多有一個匹配行,它將在查詢開始時被讀取。因為僅有一行,在這行的列值可被優化器剩余部分認為是常數。const用于用常數值比較PRIMARY KEY或UNIQUE索引的所有部分時。
eq_ref:對于每個來自于前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用并且索引是UNIQUE或PRIMARY KEY。eq_ref可以用于使用= 操作符比較的帶索引的列。比較值可以為常量或一個使用在該表前面所讀取的表的列的表達式。
ref:對于每個來自于前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。如果聯接只使用鍵的最左邊的前綴,或如果鍵不是UNIQUE或PRIMARY KEY(換句話說,如果聯接不能基于關鍵字選擇單個行的話),則使用ref。如果使用的鍵僅僅匹配少量行,該聯接類型是不錯的。ref可以用于使用=或<=>操作符的帶索引的列。
ref_or_null:該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
index_merge:該聯接類型表示使用了索引合并優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
unique_subquery:該類型替換了下面形式的IN子查詢的ref:value IN (SELECT primary_key FROMsingle_table WHERE some_expr);unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
index_subquery:該聯接類型類似于unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)
range:只檢索給定范圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引。key_len包含所使用索引的最長關鍵元素。在該類型中ref列為NULL。當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比較關鍵字列時,可以使用range
index:該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
all:對于每個來自于先前的表的行組合,進行完整的表掃描。如果表是第一個沒標記const的表,這通常不好,并且通常在它情況下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常數值或列值被檢索出。
(5)possible_keys:possible_keys列指出MySQL能使用哪個索引在該表中找到行。注意,該列完全獨立于EXPLAIN輸出所示的表的次序。這意味著在possible_keys中的某些鍵實際上不能按生成的表次序使用。
(6)key:key列顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
(7)key_len:key_len列顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。注意通過key_len值我們可以確定MySQL將實際使用一個多部關鍵字的幾個部分。
(8)ref:ref列顯示使用哪個列或常數與key一起從表中選擇行。
(9)rows:rows列顯示MySQL認為它執行查詢時必須檢查的行數。
(10)Extra:該列包含MySQL解決查詢的詳細信息。
Distinct:MySQL發現第1個匹配行后,停止為當前的行組合搜索更多的行。
Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行后,不再為前面的的行組合在該表內檢查更多的行。
range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。對前面的表的每個行組合,MySQL檢查是否可以使用range或index_merge訪問方法來索取行。
Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。通過根據聯接類型瀏覽所有行并為所有匹配WHERE子句的行保存排序關鍵字和行的指針來完成排序。然后關鍵字被排序,并按排序順序檢索行。
Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。當查詢只使用作為單一索引一部分的列時,可以使用該策略。
Using temporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。典型情況如查詢包含可以按不同情況列出列的GROUP BY和ORDER BY子句時。
Using where:WHERE子句用于限制哪一個行匹配下一個表或發送到客戶。除非你專門從表中索取或檢查所有行,如果Extra值不為Using where并且表聯接類型為ALL或index,查詢可能會有一些錯誤。
Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合并索引掃描。
Using index for group-by:類似于訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。并且,按最有效的方式使用索引,以便對于每個組,只讀取少量索引條目。
通過相乘EXPLAIN輸出的rows列的所有值,你能得到一個關于一個聯接如何的提示。這應該粗略地告訴你MySQL必須檢查多少行以執行查詢。當你使用max_join_size變量限制查詢時,也用這個乘積來確定執行哪個多表SELECT語句。
到此,相信大家對“mysql的索引技巧有哪些”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。