1.索引的優勢sql
索引可讓服務器快速地定位到表的指定位置。總結下來有三大優勢:服務器
2.高性能的索引策略工具
獨立的列性能
咱們一般會看到一些查詢不當地使用索引,或者使得Mysql沒法使用已有的索引,好比:優化
SELECT ID FROM B WHERE ID + 1 = 5; spa
Mysql沒法解析這個方程式,咱們應該養成簡化where條件的習慣,下面是另外一個常見錯誤:3d
SELECT A FROM B TO_DAYS(CURRENT_DATE) - TO_DAYS(date) <= 10; code
前綴索引和索引選擇性blog
有時候須要索引很長的字符列,這會讓索引變得大且慢。一般能夠索引開始的部分字符,這樣能夠大大節約索引空間,從而提升索引效率。但這樣會下降索引的選擇性。索引的選擇性指不重複的索引值和數據表的記錄總數的比值,比值越高表示選擇性越好。排序
通常來講,對於BLOB、TEXT或者很長的VARCHAR類型的列來講,必須使用前綴索引,由於Mysql不容許索引這些列的完整長度,那麼如何選取合適的前綴長度又不失選擇性呢,咱們來作個實驗:
//建立一個只含有字符串的數據表 CREATE TABLE `demo` ( name varchar(50) not null ); //往裏面插入1000000條亂序字符串 CALL `insert_demo`(1000000);
下面咱們觀察下數據表:
select count(distinct name) / count(*) from demo; select count(distinct LEFT(name,7)) / count(*) from demo; select count(distinct LEFT(name,9)) / count(*) from demo; select count(distinct LEFT(name,11)) / count(*) from demo; select count(distinct LEFT(name,12)) / count(*) from demo; select count(distinct LEFT(name,13)) / count(*) from demo;
能夠看到取前綴長度爲11,12,13時,選擇性已跟第一條基準很是接近,取其中任一長度均可以。只看平均選擇性是不夠的,還須要看數據分佈均不均勻。
//好比取的是11,可對比取11個長度與取總長度的數據分佈對比,你們能夠自行實驗 SELECT COUNT(*) as ant, LEFT(name, 11) as pref FROM demo GROUP BY pref ORDER BY cnt DESC LIMIT 5;//對比 SELECT COUNT(*) as ant, name as pref FROM demo GROUP BY pref ORDER BY cnt DESC LIMIT 5;//基準
前綴索引是一種能使索引更小,更快的方法,但也有個缺點,就是沒法使用前綴索引進行覆蓋掃描。一個常見的場景就是對很長的ID字段進行前綴索引。
多列索引
上一節討論過索引順序問題,好比如下狀況:
//把where條件裏面的列都建上索引
CREATE TABLE t (
c1 INT,
c2 INT,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);
在複雜場景下,這些索引並不是最好,比最優的索引還要差幾個數量級。單列索引並不能提升Mysql的查詢性能,常見策略有「索引合併」,下面咱們來討論一下
如下面的查詢爲例:
SELECT * FROM payment WHERE staff_id = 2 AND customer_id = 584;
這裏應該建立一個(staff_id,customer_id)索引仍是應該顛倒如下順序?咱們先看看各個WHERE條件分支對於的數據基數有多大:
根據經驗法則,應該將索引列customer_id放在前面,由於其對應的數據量更小,咱們再來看看對customer_id的條件值,對應的staff_id列的選擇性如何:
這裏須要注意的是,查詢結果很是依賴於選定的具體值,若是按上述優化可能對其餘條件的查詢不公平,服務器的總體性能也不見得會變好,若是是從pt-query=digest這樣的工具提取的「最差」查詢,那麼再按上述辦法選定索引順序纔會變得更加高效。
customer_id的選擇性更高,所以customer_id做爲索引第一列。
最後,儘管關於選擇性和基數的經驗法則值得去研究和分析,但必定要記住別忘了where子句的排序、分組和範圍條件等其餘因素,這些因素可能對查詢的性能找出很是大的影響。