索引
名稱解釋
- 索引
索引是一種數據結構。數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。索引的實現通常使用B樹及其變種B+樹。
更通俗的說,索引就相當於目錄。為了方便查找書中的內容,通過對內容建立索引形成目錄。索引是一個文件,它是要占據物理空間的。 - 聚簇索引
聚簇索引就是按照每張表的主鍵構造一顆B+樹,同時葉子節點中存放的就是整張表的行記錄數據,也將聚集索引的葉子節點稱為數據頁。這個特性決定了索引組織表中數據也是索引的一部分,每張表只能擁有一個聚簇索引。innodb通過主鍵聚集數據,如果沒有定義主鍵,innodb會選擇非空的唯一索引代替。如果沒有這樣的索引,innodb會隱式的定義一個主鍵來作為聚簇索引。 - 非聚簇索引(輔助索引)
在聚簇索引之上創建的索引稱之為輔助索引,輔助索引訪問數據大部分情況下需要二次查找。輔助索引葉子節點存儲的不再是行的記錄數據,而是主鍵值或行的物理地址。通過輔助索引首先找到的是主鍵值或物理地址,再通過二次查找找到數據。 - 索引覆蓋
①:如果要查詢的字段都建立過索引,那么引擎會直接在索引表中查詢而不會訪問原始數據(否則只要有一個字段沒有建立索引就會做全表掃描),這叫索引覆蓋。
因此我們需要盡可能的在select后只寫必要的查詢字段,以增加索引覆蓋的幾率。
不要想着為每個字段建立索引,因為優先使用索引的優勢就在於其體積小。
②:查詢語句的執行只用從索引中就能夠取得,不必從數據表中讀取,Innodb的主鍵查詢就支持索引覆蓋。
索引類型
-
主鍵索引
數據列不允許重復,不允許為Null,一個表只能有一個主鍵。 -
唯一索引
數據列不允許重復,允許為NULL值,一個表允許多個列創建唯一索引。
在sql server中,唯一索引字段不能出現多個null值;
在mysql 的innodb引擎中,是允許在唯一索引的字段中出現多個null值的。 -
普通索引
基本的索引類型,沒有唯一性的限制,允許為NULL值。 -
全文索引
是目前搜索引擎使用的一種關鍵技術。
可以通過ALTER TABLE table_name ADD FULLTEXT(column),創建全文索引。在MySQL 5.6版本以前,只有MyISAM存儲引擎支持全文引擎.在5.6版本中,InnoDB加入了對全文索引的支持,但是不支持中文全文索引.在5.7.6版本,MySQL內置了ngram全文解析器,用來支持亞洲語種的分詞.
索引數據結構
簡介
索引的數據結構和具體存儲引擎的實現有關,在MySQL中使用較多的索引有Hash索引,B+樹索引等,而我們經常使用的InnoDB存儲引擎的默認索引實現為:B+樹索引。
- B樹索引
Mysql數據庫中使用頻繁的索引類型,基本所有存儲引擎都支持BTree索引。通常我們說的索引不出意外指的就是(B樹)索引(實際是用B+樹實現的,因為在查看表索引時,mysql一律打印BTREE,所以簡稱為B樹索引)
可用於=,>,>=,<,<=,between和like這些比較操作符上,即只要它的查詢條件是一個不以通配符開頭的常量,如: like 'jack%'。
- 哈希索引
當我們在mysql中用哈希索引時,主要就是通過Hash算法(常見的Hash算法有直接定址法、平方取中法、折疊法、除數取余法、隨機數法),將數據庫字段數據轉換成定長的Hash值,與這條數據的行指針一並存入Hash表的對應位置;如果發生Hash碰撞(兩個不同關鍵字的Hash值相同),則在對應Hash鍵下以鏈表形式存儲。
只能用於對等(=)比較符,由於是一次定位數據,不像BTree索引需要從根節點到枝節點,后才能訪問到頁節點這樣多次IO訪問,所以檢索效率遠高於BTree索引。
索引創建
創建原則
- 較頻繁作為查詢條件的字段才去創建索引,更新頻繁字段不適合創建索引;
- 若是不能有效區分數據的列不適合做索引列(如性別,男女未知,多也就三種,區分度實在太低);
- 使用短索引,如果對長字符串列進行索引,應該指定一個前綴長度,這樣能夠節省大量索引空間;
- 左前綴匹配原則,組合索引非常重要的原則,mysql會一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a=1 and b=2 and c>3 and d=4如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。
- 盡量的擴展索引,不要新建索引。比如表中已經有a的索引,現在要加(a,b)的索引,那么只需要修改原來的索引即可。
- 定義有外鍵的數據列一定要建立索引。
- 不要過度索引。索引需要額外的磁盤空間,並降低寫操作的性能。在修改表內容的時候,索引會進行更新甚至重構,索引列越多,這個時間就會越長。所以只保持需要的索引有利於查詢即可。
- 對於定義為text、image和bit的數據類型的列不要建立索引。
創建注意事項
- 非空字段:應該指定列為NOTNULL,除非你想存儲NULL。在mysql中,含有空值的列很難進行查詢優化,因為它們使得索引、索引的統計信息以及比較運算更加復雜。你應該用0、一個特殊的值或者一個空串代替空值;
- 取值離散大的字段:(變量各個取值之間的差異程度)的列放到聯合索引的前面,可以通過count()函數查看字段的差異值,返回值越大說明字段的唯一值越多字段的離散程度高;
- 索引字段越小越好:數據庫的數據存儲以頁為單位一頁存儲的數據越多一次IO操作獲取的數據越大效率越高。
索引的增刪改
創建
- 創建表的時候創建
CREATE TABLE user_index2(
id INT AUTO_INCREMENT PRIMARY KEY, -- 聚焦索引(主鍵索引),設置PRIMARY KEY時即創建
first_name VARCHAR(16),
last_name VARCHAR(16),
id_card VARCHAR(18),
information text,
KEY name(first_name,last_name), -- KEY 普通索引
FULLTEXT KEY(information), -- FULLTEXT 創建全文索引
UNIQUE KEY(id_card) -- UNIQUE 唯一索引
);
注: mysql中主鍵創建最好不要與業務相關連,阿里巴巴開發手冊中也有提到。
- 使用Alter table 命令增加索引
- 創建唯一索引
ALTER TABLE table_name ADD UNIQUE(column); - 創建唯一組合索引
ALTER TABLE table_name ADD UNIQUE(column1,column2); - 創建普通索引
ALTER TABLE table_name ADD INDEX index_name(column); - 創建普通組合索引
ALTER TABLE table_name ADD INDEX index_name(column1,column2,column3); - 創建主鍵索引
ALTER TABLE table_name ADD PRIMARY KEY ( column ); - 創建全文索引
ALTER TABLE table_name ADD FULLTEXT ( column );
- 創建唯一索引
查看索引
show index from user_index
- 注釋
- Table 表的名稱;
- Non_unique 如果索引不能包括重復詞,則為0。如果可以,則為1;
- Key_name 索引的名稱;
- Seq_in_index 索引中的列序列號,從1開始;
- Column_name 列名稱;
- Collation 列以什么方式存儲在索引中。在MySQL中,有值‘A’(升序,B+樹索引此值為A)或NULL(無分類);
- Cardinality 表中唯一值的估計個數;此列越接近行數越好,如果太小,要考慮去掉;同時優化器會根據這個值判斷是否使用這個索引,這個值更新會有些延遲,手動觸發更新使用analyze table命令,同時該值不是精確值,為數據采樣值,系統自動觸發條件為:數據調整1/16時或數據修改大於2 000 000 000次時;
- Sub_part 如果列只是被部分地編入索引,則為被編入索引的字符的數目。如果整列被編入索引,則為NULL;
- Packed 指示關鍵字如何被壓縮。如果沒有被壓縮,則為NULL;
- Null 如果列含有NULL,則含有YES。如果沒有,則該列含有NO;
- Index_type 索引類型;
- comment:注釋;
刪除索引
- 刪除普通索引、唯一索引、全文索引
格式: alter table 表名 drop KEY 索引名
alter table user_index drop KEY name;
alter table user_index drop KEY id_card;
alter table user_index drop KEY information;
- 刪除主鍵索引
格式:alter table 表名 drop primary key(因為主鍵只有一個)
如果主鍵自增長,那么不能直接執行此操作(自增長依賴於主鍵索引),需取消自增長再行刪除
alter table user_index
-- 重新定義字段
MODIFY id int,
drop PRIMARY KEY
修改索引
mysql中沒有真正意義上的修改索引,只有先刪除之后在創建新的索引才可以達到修改的目的,原因是mysql在創建索引時會對字段建立關系長度等,只有刪除之后創建新的索引才能創建新的關系保證索引的正確性;
即先行索引刪除再創建索引
sql語句分析索引使用情況
explain select * from user_index2 where first_name=11;
explain和desc關鍵字會模擬優化器執行sql查詢語句,從而知道MySQL如何處理sql語句。進而分析。
- 注釋
- id 實際執行順序 id 越大越先執行 id相同 執行從上到下;
- select type 查詢類型 包含 simple(簡單查詢) primary(任何包含復雜子查詢的最外層查詢) subquery(select 或 where列表中包含了子查詢) derived(在from列表中包含了子查詢被標記為DERIVE的衍生,mysql遞歸執行這鞋子查詢把結果放在臨時表中) union(若第二個select語句出現在union之后則被標記為union,若union包含在from字句子查詢中外層select標記為derived) unionresult(從union表中獲取結果的select)等;
- table 操作的表;
- type 查詢使用了那些類型system>const>eq_ref>ref>range>index>all
- possible_keys 可能用到了索引
- key 實際用到的索引
- key_len 表示索引中使用的字節數 可通過計算查詢中使用的索引的長度。在不損失精度前提下,長度越短越好。是索引字段的最大可能長度,並非實際使用長度。
- ref 顯示索引的那一列被使用了。如果可能的話,是一個常數。
- rows 根據表統計信息即索引選用情況,大直沽算出找到所需記錄須讀取的行數。
- Extra 不適合出現在其他列的十分重要的額外信息。可能出現以下信息
- Using filesort mysql使用了外部的索引排序而不是按照表內索引順序進行讀取。mysql無法利用索引完成的排序操作稱為 “文件排序” (不好)
- Using temporary 使用了臨時表保存中間結果。MySQL在對查詢結果排序時使用了臨時表。常見於order by和分組查詢 group by。 (不好)
- Using Index 使用了索引覆蓋,效率不錯。如果同時出現using where 表明索引被用來 執行鍵值的查找。
其他
百萬級別或以上的數據如何刪除
關於索引:由於索引需要額外的維護成本,因為索引文件是單獨存在的文件,所以當我們對數據的增加,修
改,刪除,都會產生額外的對索引文件的操作,這些操作需要消耗額外的IO,會降低增/改/刪的執行效率。所
以,在我們刪除數據庫百萬級別數據的時候,查詢MySQL官方手冊得知刪除數據的速度和創建的索引數
量是成正比的。
- 所以我們想要刪除百萬數據的時候可以先刪除索引(此時大概耗時三分多鍾)
- 然后刪除其中無用數據(此過程需要不到兩分鍾)
- 刪除完成后重新創建索引(此時數據較少了)創建索引也非常快,約十分
鍾左右。 - 與之前的直接刪除絕對是要快速很多,更別說萬一刪除中斷,一切刪除會回滾。那更是坑了。
MyISM使用的索引和Innodb的索引的區別
①:Innodb主鍵索引是聚集索引;MyISM主鍵索引是非聚集索引。
②:Innodb非聚簇索引使用的是B-Tree樹,主鍵索引使用的是B+Tree。MyISAM使用B-Tree實現主鍵索引、唯一索引和非主鍵索引。
③:Innodb非聚簇索引存儲的是主鍵值,MyISAM非聚簇索引存儲的是數據的物理地址。
聚簇索引的優缺點
優點:
1.數據訪問更快,因為聚簇索引將索引和數據保存在同一個B+樹中,因此從聚簇索引中獲取數據比非聚簇索引更快
2.聚簇索引對於主鍵的排序查找和范圍查找速度非常快
缺點:
1.插入速度嚴重依賴於插入順序,按照主鍵的順序插入是最快的方式,否則將會出現頁分裂,嚴重影響性能。因此,對於InnoDB表,我們一般都會定義一個自增的ID列為主鍵
2.更新主鍵的代價很高,因為將會導致被更新的行移動。因此,對於InnoDB表,我們一般定義主鍵為不可更新。
3.二級索引訪問需要兩次索引查找,第一次找到主鍵值,第二次根據主鍵值找到行數據。
參考
MySQL刪除數據:https://www.cnblogs.com/yhtboke/p/14229511.html;
聚簇索引和非聚簇索引:https://www.cnblogs.com/jiawen010/p/11805241.html。