索引
- 索引并不是越多越好谆构,要根據(jù)查詢有針對性的創(chuàng)建,考慮在WHERE和ORDER BY命令上涉及的列建立索引铡买,可根據(jù)EXPLAIN來查看是否用了索引還是全表掃描
- 應(yīng)盡量避免在WHERE子句中對字段進行NULL值判斷更鲁,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描
- 值分布很稀少的字段不適合建索引,例如"性別"這種只有兩三個值的字段
- 字符字段只建前綴索引
- 字符字段最好不要做主鍵
- 不用外鍵奇钞,由程序保證約束
- 盡量不用UNIQUE澡为,由程序保證約束
- 使用多列索引時主意順序和查詢條件保持一致,同時刪除不必要的單列索引
簡言之就是使用合適的數(shù)據(jù)類型景埃,選擇合適的索引
選擇合適的數(shù)據(jù)類型
(1)使用可存下數(shù)據(jù)的最小的數(shù)據(jù)類型媒至,整型 < date,time < char,varchar < blob
(2)使用簡單的數(shù)據(jù)類型,整型比字符處理開銷更小谷徙,因為字符串的比較更復(fù)雜拒啰。如,int類型存儲時間類型完慧,bigint類型轉(zhuǎn)ip函數(shù)
(3)使用合理的字段屬性長度谋旦,固定長度的表會更快。使用enum骗随、char而不是varchar
(4)盡可能使用not null定義字段
(5)盡量少用text蛤织,非用不可最好分表
選擇合適的索引列
(1)查詢頻繁的列,在where鸿染,group by指蚜,order by,on從句中出現(xiàn)的列
(2)where條件中<涨椒,<=摊鸡,=,>蚕冬,>=免猾,between,in囤热,以及l(fā)ike 字符串+通配符(%)出現(xiàn)的列
(3)長度小的列猎提,索引字段越小越好,因為數(shù)據(jù)庫的存儲單位是頁旁蔼,一頁中能存下的數(shù)據(jù)越多越好
(4)離散度大(不同的值多)的列锨苏,放在聯(lián)合索引前面。查看離散度棺聊,通過統(tǒng)計不同的列值來實現(xiàn)伞租,count越大,離散程度越高:
關(guān)于前綴索引
有時候需要索引很長的字符列限佩,這會讓索引變得大且慢葵诈。通陈阆遥可以索引開始的部分字符,這樣可以大大節(jié)約索引空間作喘,從而提高索引效率理疙。但這樣也會降低索引的選擇性。索引的選擇性是指不重復(fù)的索引值(也稱為基數(shù)徊都,cardinality)和數(shù)據(jù)表的記錄總數(shù)的比值沪斟,范圍從1/#T到1之間。索引的選擇性越高則查詢效率越高暇矫,因為選擇性高的索引可以讓MySQL在查找時過濾掉更多的行主之。唯一索引的選擇性是1,這是最好的索引選擇性李根,性能也是最好的槽奕。
一般情況下某個前綴的選擇性也是足夠高的,足以滿足查詢性能房轿。對于BLOB(BLOB (binary large object)粤攒,二進制大對象,是一個可以存儲二進制文件的“容器”囱持。)夯接,TEXT,或者很長的VARCHAR類型的列纷妆,必須使用前綴索引盔几,因為MySQL不允許索引這些列的完整長度。
一個查詢中針對不同前綴長度的選擇性進行計算掩幢,這對于大表非常有用逊拍,下面給出如何在同一個查詢中計算不同前綴長度的選擇性:
mysql> select count(distinct left(city,3))/count() as sel3,
-> count(distinct left(city,4))/count() as sel4,
-> count(distinct left(city,5))/count() as sel5,
-> count(distinct left(city,6))/count() as sel6
-> from city_demo;
可以看見當(dāng)索引前綴為6時的基數(shù)是0.4267,已經(jīng)接近完整列選擇性0.4283际邻。
在上面的示例中芯丧,已經(jīng)找到了合適的前綴長度,下面創(chuàng)建前綴索引:
mysql> alter table city_demo add key (city(6));
前綴索引是一種能使索引更小世曾,更快的有效辦法缨恒,但另一方面也有其缺點:
mysql無法使用其前綴索引做ORDER BY和GROUP BY,也無法使用前綴索引做覆蓋掃描轮听。
覆蓋索引
通常大家會根據(jù)查詢的WHERE條件來創(chuàng)建合適的索引骗露,不過這只是索引優(yōu)化的一個方面。設(shè)計優(yōu)秀的索引應(yīng)該考慮到整個查詢蕊程,而不單單是WHERE條件部分。索引確實是一種查找數(shù)據(jù)的高效方式驼唱,但是MySQL也可以使用索引來直接獲取列的數(shù)據(jù)藻茂,這樣就不需要讀取數(shù)據(jù)行。如果索引的葉子節(jié)點中已經(jīng)包含要查詢的數(shù)據(jù),那么還有什么必要回表查詢呢辨赐?如果一個索引包含(或者說覆蓋)所有需要查詢的字段的值优俘,我們就稱之為“覆蓋索引”。
不是所有類型的索引都可以稱為覆蓋索引掀序。覆蓋索引必須要存儲索引列的值帆焕,而哈希索引、空間索引和全文索引等都不存儲索引列的值不恭,所以MySQL只能使用B-Tree索引做覆蓋索引叶雹。另外,不同的存儲引擎實現(xiàn)覆蓋索引的方式也不同换吧,而且不是所有的引擎都支持覆蓋索引折晦。
使用總結(jié)
開發(fā)中需要注意的點
MySQL帶索引的字段類型修改了,如:從int改為varchar沾瓦。PHP的sql查詢語句也要做相應(yīng)修改满着,
$sql = 'select * from tb where trade_id='.(string)$trade_id;
這里如果不做強制類型轉(zhuǎn)換,sql查詢時將不使用索引贯莺。