索引對提高SELECT/UPDATE語句查詢速度有着立竿見影的效果,有索引和無索引,查詢速度每每差幾個數量級。html
本次討論一下index(每列做爲一個索引,單列索引)和Multiple-Column Indexes(多列做爲一個索引,最多16列,複合索引)使用場景。mysql
方式一,建表時新建sql
CREATE TABLE test ( id INT NOT NULL, last_name CHAR(30) NOT NULL, first_name CHAR(30) NOT NULL, PRIMARY KEY (id), -- 單列索引 INDEX name (last_name) -- 複合索引 -- INDEX name (last_name,first_name) );
方式二,給即存表添加索引:ide
/*單列索引*/ ALTER TABLE test ADD INDEX name (last_name); /*複合索引*/ ALTER TABLE test ADD INDEX name (last_name,first_name);
這裏要注意索引的順序很重要,關係到可否命中索引,後面詳細討論。工具
mysql官方文檔是這麼描述複合索引的:mysql能使用複合索引來查詢索引中的全部列,或者查詢複合索引中的第一列、前兩列、前三列等等。優化
若是指定列順序正確相對於索引中的定義順序,那麼一個簡單的複合做引能夠加快一個表中幾種類型的查詢。官網地址spa
以上這段話包可解讀以下:code
簡單的說加入複合索引的順序是(col1, col2, col3)那麼WHERE語句中的(col1)、(ol1, col2)、(col1, col2, col3)都能命中索引,可是(col2)、(col3)、(ol2, col3)是不能命中索引規則的,由於不知足最左前綴規則。htm
舉個栗子,假設新建複合索引以下:blog
CREATE TABLE test ( id INT NOT NULL, last_name CHAR(30) NOT NULL, first_name CHAR(30) NOT NULL, PRIMARY KEY (id), INDEX name (last_name,first_name) );
根據最左前綴原則,如下查詢語句能命中索引:
SELECT * FROM test WHERE last_name='Widenius'; SELECT * FROM test WHERE last_name='Widenius' AND first_name='Michael'; SELECT * FROM test WHERE last_name='Widenius' AND (first_name='Michael' OR first_name='Monty'); SELECT * FROM test WHERE last_name='Widenius' AND first_name >='M' AND first_name < 'N';
如下查詢語句不能命中複合索引:
SELECT * FROM test WHERE first_name='Michael'; SELECT * FROM test WHERE last_name='Widenius' OR first_name='Michael';
若是不清楚是否命中索引,EXPLAIN是個好工具,要充分利用起來。好比下語句,查看結果中的key就能知道是否命中,爲空就是木有命中:
EXPLAIN SELECT * FROM test WHERE first_name='Michael';
在作報表集計通常會使用ETL工具抽取業務數據插入到事實表中,就好比使用kettle update/insert,其內部原理都是先查詢不存在就如插入數據,存在數據就更新。
所以若是數據不少的話就會有不少的查詢動做,而且是多條件查詢。這種狀況複合索引效率是最高的,可是每每實際的業務中還會以單列做爲查詢的場合這是就須要普通索引來知足這個需求。
這種場合就會出現同一列同時出如今了複合索引和單列索引中,這也是很正常的。給一個實際的例子以下:
CREATE TABLE `st_stock` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增ID', `id_company` int(11) NOT NULL COMMENT '組織維度', `id_date` int(11) NOT NULL COMMENT '日期維度', `id_part` int(11) NOT NULL COMMENT '材料維度', `number` decimal(18,2) DEFAULT NULL COMMENT '出庫數量', `subtotal` decimal(21,6) DEFAULT NULL COMMENT '出庫金額', PRIMARY KEY (`id`), KEY `IDX_ORG` (`id_company`), KEY `IDX_PART` (`id_part`), KEY `IDX_DATE_ORG_PART` (`id_date`,`id_company`,`id_part`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='xxxxxx';
#2498和#2499數據量大於等於#249六、#2497,但集計時間將近縮短了一半,效果仍是很明顯。
優化效果沒有達到一個數量或更高級是由於優化的只是JOB中一個轉換,只是優化的衆多因素之一。
即使如此也達到了預期的效果。
最後還要注意一點,索引的維護是有代價的,並非越多越好。其餘參考資料以下:
https://www.percona.com/blog/2009/09/19/multi-column-indexes-vs-index-merge/
https://www.percona.com/blog/2014/01/03/multiple-column-index-vs-multiple-indexes-with-mysql-56/
https://dev.mysql.com/doc/refman/5.7/en/drop-index.html
https://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html