一、索引類型
- 主鍵索引
一種特殊的唯一索引,不允許有空值,一般是在建表的時候同時創建索引。注意:一個表只能有一個主鍵
- 唯一索引
唯一索引的值必須唯一,但允許有空值。如果是組合索引,則列值得組合必須唯一。
-- 創建唯一索引
ALTER TABLE table_name ADD UNIQUE(column)
- 普通索引
最基本的索引,沒有任何限制
-- 創建普通索引
ALTER TABLE table_name ADD INDEX index_name(column)
- 組合索引
一個索引包含多個列,多用於避免回表查詢
--創建組合索引
ALTER TABLE table_name ADD INDEX index(column1,column2,column3)
- 全文索引
也稱全文檢索,是目前搜索引擎使用的關鍵技術
-- 創建全文索引
ALTER TABLE table_name ADD FULLTEXT(column)
索引創建後不能更改,如果要修改索引,只能刪除重建
刪除索引
DROP INDEX index_name ON table_name
查詢索引詳情
show index from table_name;
二、索引優化
- 前導模糊查詢不能命中索引
EXPLAIN SELECT * from test_user where name like '%王%'
非前導模糊查詢可以使用索引,可優化爲使用後置模糊查詢
EXPLAIN SELECT * from test_user where name like '王%'
- 數據類型出現隱式轉換的時候不會命中索引,特別是當列類型是字符串,一定要將字符常量值用引號引起來。
EXPLAIN SELECT * from test_user where name = 3;
EXPLAIN SELECT * from test_user where name = '3';
- 組合索引(最左原則),查詢條件是否包含最左側字段
alter table test_user add index index_zuhe(name,age,gender)
表中索引情況
根據最左原則,可以命中組合索引index_zuhe
EXPLAIN SELECT * from test_user where name = '王天' and age = 18;
注意,最左原則並不是說是查詢條件的順序:這樣也可命中
EXPLAIN SELECT * from test_user where age = 18 and name = '王天' and gender = '男';
而是查詢條件中是否包含索引最左列字段:
EXPLAIN SELECT * from test_user where age = 18 and gender = '男';
- union、in、or都能夠命中索引
EXPLAIN SELECT * from test_user where age = 18
union all
SELECT * from test_user where age = 19
EXPLAIN SELECT * from test_user where age in (11,12);
EXPLAIN SELECT * from test_user where age =11 or age = 12;
- 用or分割開的條件,如果or前的條件中列有索引,而後面的列中沒有索引,那麼涉及到的索引都不會被用到。
EXPLAIN SELECT * from test_user where age=18 or gender='男'
因爲or後面的條件列中沒有索引,那麼後面的查詢肯定要走全表掃描,在存在全表掃描的情況下,就沒有必要多一次索引掃描增加IO訪問。
- 負向條件查詢不能使用索引,可以優化爲in查詢。
負向條件有:!=、<>、not in、not exists、not like等。
!= 不能命中索引
EXPLAIN SELECT * from test_user where age !=18
is not null 不能命中索引
EXPLAIN SELECT * from test_user where age is not null;
is null 可以命中索引
EXPLAIN SELECT * from test_user where age is null;
- 數據庫執行計算不會命中索引。
EXPLAIN SELECT * from test_user where age >=27;
EXPLAIN SELECT * from test_user where age +1>=27;
- 建立索引的列,不允許爲null。
單列索引不存null值,複合索引不存全爲null的值,如果列允許爲null,可能會得到“不符合預期”的結果集,所以,請使用not null約束以及默認值。
三、索引設計的原則
- 適合索引的列是出現在where子句中的列,或者連接子句中指定的列;
- 基數較小的類,索引效果較差,沒有必要在此列建立索引;
- 使用短索引,如果對長字符串列進行索引,應該指定一個前綴長度,這樣能夠節省大量索引空間;
- 不要過度索引。索引需要額外的磁盤空間,並降低寫操作的性能。在修改表內容的時候,索引會進行更新甚至重構,索引列越多,這個時間就會越長。所以只保持需要的索引有利於查詢即可。
另外返回數據的比例在30%以外的情況下,優化器不會選擇使用索引。
例1:test_user表一共有17條數據,age>16 的共查詢到7條數據,那麼這個查詢是否可以命中呢?
EXPLAIN SELECT * from test_user where age > 16
例2:如果我把條件改了 ,改成age>19共查詢到4條數據,那麼是否可以命中呢?
EXPLAIN SELECT * from test_user where age > 19;
答案是例1不能命中索引,例2可以命中索引。
例1執行結果
例2執行結果
注意filtered的值就是上面我們計算的返回記錄的比例數;
因此,返回表中30%內的數據會走索引,返回超過30%數據就使用全表掃描。當然這個結論太絕對了,也並不是絕對的30%,只是一個大概的範圍。
總結
平時的開發中經常用到sql,也會對sql進行優化,對於拿捏不準的,多使用EXPLAIN命令分析一下。