Mysql-高性能索引策略
正確的創建和使用索引是實現高性能查詢的基礎。我總結了以下幾點索引選擇的策略和索引的注意事項:
索引的使用策略:
(PS:索引的選擇性是指:不重復的索引值,和數據表的記錄總數(#T)的比值 ,范圍從1/#T 到1之間,索引的選擇性越高則查詢效率越高,因為選擇性搞得索引可以讓Mysql在查找時可以過濾更多的行。唯一索引的選擇性是1,這是最好的索引選擇性,性能也是更好
計算列的選擇性例子: mysql> select count(distinct city)/ count(*) from city_demo )
1.為很長的字符列建立索引,應使用前綴索引(或者使用哈希索引多維護一個hash列),前綴索引是一種能使索引更小,更快的有效辦法。選擇前綴的長度要保證有較高的選擇性。
(原因:索引過長的字符列,會讓索引變的大而且慢。)
缺陷:Mysql無法使用前綴索引和哈希索引做order by 和 group by,也無法使用前綴索引和哈希索引做覆蓋掃描。
2.選擇合適的索引列順序構建復合索引(需要考慮WHERE 條件,排序和分組等情況。當不需要考慮排序和分組時,將選擇性更高的列放在前面通常時比較好的,同時也需要結合WHERE 查詢條件中列 的出現頻率的高低來調整索引列的順序)
3.盡量使用索引掃描來做排序
(注意事項:只有當索引的列順序和order by 子句 順序完全一致,並且所有列的排序方向(倒序或正序)Mysql才能使用索引排序。如果查詢需要關聯多張表,則只有當 order by 子句的字段全部為第一個表時,才能使用索引做排序。 order by 子句使用索引排序也需要遵循最左前綴原則。
EXPLAN 分析執行語句,如果type列的值為“index”,則說明mysql 使用了索引掃描來做排序)
4.大多數情況不需要冗余索引,應該盡量擴展已有的索引而不是創建新索引。但也有時候出於性能方面的考慮需要冗余索引。因為擴展已有的索引會導致其變得太大,從而影響其他使用該索引的查詢性能。
5.查詢考慮覆蓋索引,覆蓋索引不需要回表查詢,效率更高。
(注意事項:雖然覆蓋查詢效率更好,但也不能一味的為了覆蓋查詢把所有查詢返回的列都加上索引,索引越多,mysql插入速度越慢)
總結:
總的來說,編寫查詢語句應該盡可能選擇合適的索引來避免單行查找,盡可能地使用數據的原生順序從而避免額外的排序操作,並盡可能的使用索引覆蓋查詢。
一些索引不生效的例子總結:
假如有如下數據表 create table user (
name varchar(30) not null,
birthday date not null,
address varchar(100) not null,
age int(5) not null,
card varchar(18) not null,
createtime date not null,
key(name,birthday,adress),
key(age),
key(card)
);
1. select * from user where name="李先生" and adress="北京" and birthday="2011-11-11";
adress 和birthday列不走索引
(原因:違反最左前綴原則,順序與復合索引順序不一致)
2.select * from user where name="李先生" and birthday >"2011-11-11" and adress="北京" ;
adress 列不走索引
(原因:birthday 列的查詢條件為范圍查詢,其右邊的所有列都無法使用索引優化查詢)
3.select * from user where name like "%李";
name 列不走索引
(原因:最左前綴匹配原則 ,like '李%' 走索引)
4.select * from user where name like "李%" and birthday="2011-11-11";
birthday 列不走索引
(原因:like '李%' 也屬於范圍查詢 與第二條一致)
5.select * from user where age+10=30;
age 列不走索引
(原因:參與計算的列不走索引)
6.select * from user where LEFT(card,6)="231084";
card 列不走索引
(原因:使用函數的列不走索引)
7.select * from user where age=20 order by name asc , birthday desc;
order by 不能使用 索引掃描排序
(原因:雖然 order by 后的兩個列 組成了最左前綴,但這個查詢使用了兩種不同的排序方向,索引列都是正序排列的)
8.select * from user where name like "李%" order by birthday;
order by 不能使用索引掃描
(原因:name 列使用了范圍查詢,復合索引其他的列不能使用索引)
9.如果類型是字符串,那一定要再條件中將數據使用引號引用起來,否則不使用索引
10.如果條件中有or 即使其中有條件索引也不會使用
(注意:要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引)