2021-01-08
索引有哪幾種類型?
主鍵索引: 資料列不允許重複,不允許為NULL,一個表只能有一個主鍵。
唯一索引: 資料列不允許重複,允許為NULL值,一個表允許多個列建立唯一索引。
可以通過 ALTER TABLE table_name ADD UNIQUE (column); 建立唯一索引
可以通過 ALTER TABLE table_name ADD UNIQUE (column1,column2); 建立唯一組合索引
普通索引: 基本的索引型別,沒有唯一性的限制,允許為NULL值。
可以通過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 FULLTEXT (column);建立全文索引
索引的資料結構(b樹,hash)
索引的資料結構和具體儲存引擎的實現有關,在MySQL中使用較多的索引有Hash索引,B+樹索引等,而我們經常使用的InnoDB儲存引擎的預設索引實現為:B+樹索引。對於雜湊索引來說,底層的資料結構就是雜湊表,因此在絕大多數需求為單條記錄查詢的時候,可以選擇雜湊索引,查詢效能最快;其餘大部分場景,建議選擇BTree索引。
1)B樹索引
mysql通過儲存引擎取資料,基本上90%的人用的就是InnoDB了,按照實現方式分,InnoDB的索引型別目前只有兩種:BTREE(B樹)索引和HASH索引。B樹索引是Mysql資料庫中使用最頻繁的索引型別,基本所有儲存引擎都支援BTree索引。通常我們說的索引不出意外指的就是(B樹)索引(實際是用B+樹實現的,因為在查看錶索引時,mysql一律列印BTREE,所以簡稱為B樹索引)
img
查詢方式:
主鍵索引區:PI(關聯儲存的時資料的地址)按主鍵查詢,
普通索引區:si(關聯的id的地址,然後再到達上面的地址)。所以按主鍵查詢,速度最快
B+tree性質:
1.)n棵子tree的節點包含n個關鍵字,不用來儲存資料而是儲存資料的索引。
2.)所有的葉子結點中包含了全部關鍵字的資訊,及指向含這些關鍵字記錄的指標,且葉子結點本身依關鍵字的大小自小而大順序連結。
3.)所有的非終端結點可以看成是索引部分,結點中僅含其子樹中的最大(或最小)關鍵字。
4.)B+ 樹中,資料物件的插入和刪除僅在葉節點上進行。
5.)B+樹有2個頭指標,一個是樹的根節點,一個是最小關鍵碼的葉節點。
2)雜湊索引
簡要說下,類似於資料結構中簡單實現的HASH表(散列表)一樣,當我們在mysql中用雜湊索引時,主要就是通過Hash演算法(常見的Hash演算法有直接定址法、平方取中法、摺疊法、除數取餘法、隨機數法),將資料庫欄位資料轉換成定長的Hash值,與這條資料的行指標一併存入Hash表的對應位置;如果發生Hash碰撞(兩個不同關鍵字的Hash值相同),則在對應Hash鍵下以連結串列形式儲存。當然這只是簡略模擬圖。
img
索引的基本原理
索引用來快速地尋找那些具有特定值的記錄。如果沒有索引,一般來說執行查詢時遍歷整張表。
索引的原理很簡單,就是把無序的資料變成有序的查詢
把建立了索引的列的內容進行排序
對排序結果生成倒排表
在倒排表內容上拼上資料地址鏈
在查詢的時候,先拿到倒排表內容,再取出資料地址鏈,從而拿到具體資料
索引演算法有哪些?
索引演算法有 BTree演算法和Hash演算法
BTree演算法
BTree是最常用的mysql資料庫索引演算法,也是mysql預設的演算法。因為它不僅可以被用在=,>,>=,<,<=和between這些比較操作符上,而且還可以用於like操作符,只要它的查詢條件是一個不以萬用字元開頭的常量, 例如:
– 只要它的查詢條件是一個不以萬用字元開頭的常量
select * from user where name like ‘jack%’;
– 如果一萬用字元開頭,或者沒有使用常量,則不會使用索引,例如:
select * from user where name like ‘%jack’;
1
2
3
4
Hash演算法
Hash Hash索引只能用於對等比較,例如=,<=>(相當於=)操作符。由於是一次定位資料,不像BTree索引需要從根節點到枝節點,最後才能訪問到頁節點這樣多次IO訪問,所以檢索效率遠高於BTree索引。
索引設計的原則?
適合索引的列是出現在where子句中的列,或者連線子句中指定的列
基數較小的類,索引效果較差,沒有必要在此列建立索引
使用短索引,如果對長字串列進行索引,應該指定一個字首長度,這樣能夠節省大量索引空間
不要過度索引。索引需要額外的磁碟空間,並降低寫操作的效能。在修改表內容的時候,索引會進行更新甚至重構,索引列越多,這個時間就會越長。所以只保持需要的索引有利於查詢即可。
建立索引的原則(重中之重)
索引雖好,但也不是無限制的使用,最好符合一下幾個原則
1) 最左字首匹配原則,組合索引非常重要的原則,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的順序可以任意調整。
2)較頻繁作為查詢條件的欄位才去建立索引
3)更新頻繁欄位不適合建立索引
4)若是不能有效區分資料的列不適合做索引列(如性別,男女未知,最多也就三種,區分度實在太低)
5)儘量的擴充套件索引,不要新建索引。比如表中已經有a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可。
6)定義有外來鍵的資料列一定要建立索引。
7)對於那些查詢中很少涉及的列,重複值比較多的列不要建立索引。
8)對於定義為text、image和bit的資料型別的列不要建立索引。
建立索引的三種方式,刪除索引
第一種方式:在執行CREATE TABLE時建立索引
CREATE TABLE user_index2 (
id INT auto_increment PRIMARY KEY,
first_name VARCHAR (16),
last_name VARCHAR (16),
id_card VARCHAR (18),
information text,
KEY name (first_name, last_name),
FULLTEXT KEY (information),
UNIQUE KEY (id_card)
);
第二種方式:使用ALTER TABLE命令去增加索引
ALTER TABLE table_name ADD INDEX index_name (column_list);
ALTER TABLE用來建立普通索引、UNIQUE索引或PRIMARY KEY索引。
其中table_name是要增加索引的表名,column_list指出對哪些列進行索引,多列時各列之間用逗號分隔。
索引名index_name可自己命名,預設時,MySQL將根據第一個索引列賦一個名稱。另外,ALTER TABLE允許在單個語句中更改多個表,因此可以在同時建立多個索引。
第三種方式:使用CREATE INDEX命令建立
CREATE INDEX index_name ON table_name (column_list);
CREATE INDEX可對錶增加普通索引或UNIQUE索引。(但是,不能建立PRIMARY KEY索引)
刪除索引
根據索引名刪除普通索引、唯一索引、全文索引: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(因為主鍵只有一個)。這裡值得注意的是,如果主鍵自增長,那麼不能直接執行此操作(自增長依賴於主鍵索引):
img
需要取消自增長再行刪除:
alter table user_index
-- 重新定義欄位
MODIFY id int,
drop PRIMARY KEY
但通常不會刪除主鍵,因為設計主鍵一定與業務邏輯無關。
建立索引時需要注意什麼?
非空欄位:應該指定列為NOT NULL,除非你想儲存NULL。在mysql中,含有空值的列很難進行查詢優化,因為它們使得索引、索引的統計資訊以及比較運算更加複雜。你應該用0、一個特殊的值或者一個空串代替空值;
取值離散大的欄位:(變數各個取值之間的差異程度)的列放到聯合索引的前面,可以通過count()函式檢視欄位的差異值,返回值越大說明欄位的唯一值越多欄位的離散程度高;
索引欄位越小越好:資料庫的資料儲存以頁為單位一頁儲存的資料越多一次IO操作獲取的資料越大效率越高。
使用索引查詢一定能提高查詢的效能嗎?為什麼
通常,通過索引查詢資料比全表掃描要快。但是我們也必須注意到它的代價。
索引需要空間來儲存,也需要定期維護, 每當有記錄在表中增減或索引列被修改時,索引本身也會被修改。 這意味著每條記錄的INSERT,DELETE,UPDATE將為此多付出4,5 次的磁碟I/O。 因為索引需要額外的儲存空間和處理,那些不必要的索引反而會使查詢反應時間變慢。使用索引查詢不一定能提高查詢效能,索引範圍查詢(INDEX RANGE SCAN)適用於兩種情況:
基於一個範圍的檢索,一般查詢返回結果集小於表中記錄數的30%
基於非唯一性索引的檢索
字首索引
語法:index(field(10)),使用欄位值的前10個字元建立索引,預設是使用欄位的全部內容建立索引。
前提:字首的標識度高。比如密碼就適合建立字首索引,因為密碼幾乎各不相同。
*實操的難度:*在於字首擷取的長度。
我們可以利用select count(*)/count(distinct left(password,prefixLen));,通過從調整prefixLen的值(從1自增)檢視不同字首長度的一個平均匹配度,接近1時就可以了(表示一個密碼的前prefixLen個字元幾乎能確定唯一一條記錄)
什麼是最左字首原則?什麼是最左匹配原則
顧名思義,就是最左優先,在建立多列索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。
最左字首匹配原則,非常重要的原則,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的順序可以任意調整。
=和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式
B樹和B+樹的區別
在B樹中,你可以將鍵和值存放在內部節點和葉子節點;但在B+樹中,內部節點都是鍵,沒有值,葉子節點同時存放鍵和值。
B+樹的葉子節點有一條鏈相連,而B樹的葉子節點各自獨立。