若mysql的一張表上有一個多列索引,那麼在編寫where條件時,究竟哪些真正起到作用了呢,跟順序有關係嗎?
本文參考(http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
假設有如下的一張表:
DROP TABLE IF EXISTS testTable;
CREATE TABLE testTable
(
ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
PORT VARCHAR(64) NOT NULL COMMENT 'port',
TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
CREATED TIMESTAMP NOT NULL COMMENT 'created time',
PRIMARY KEY(ID),
UNIQUE KEY INDEX_WORKER_NODE(HOST_NAME,PORT,LAUNCH_DATE,TYPE)
)COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;
對應的查詢語句分別是:
select * from testTable where PORT=3306 and Type=1
select * from testTable where PORT=3307 and HOST_NAME='172.21.1.1'
select * from testTable where PORT=3308 AND HOST_NAME='172.21.1.2' AND TYPE=2
第一句:沒用到索引,在聚集索引上從左至右依次掃描過濾;
第二句:用到了輔助索引INDEX_WORKER_NODE;
第三句:用到了輔助索引INDEX_WORKER_NODE,但是隻有HOST_NAME和PORT條件是通過索引完成的,條件TYPE是依次掃描過濾完成的;
爲什麼呢?
因爲輔助索引是B+樹實現的,雖然可以指定多個列,但是每個列的比較優先級不一樣,寫在前面的優先比較。一旦出現遺漏,在B+樹上就無法繼續搜索了(通過補齊等措施解決的除外),因此是按照最左連續匹配來的。既然是在B+樹上搜索,對於條件的比較自然是要求精確匹配(即"="和"IN")。不過順序倒是可以顛倒,因爲查詢優化器重排序一下就好了。
回頭來看,第一句,由於缺少HOST_NAME,只能在聚集索引的葉節點上,從左至右的掃描,挨個比對;
第二句,可以直接在輔助索引上查找,被找到的子樹的所有葉節點就是命中的記錄;
第三句,缺少LAUNCH_DATE條件,所以只能先依據HOST_NAME和PROT在輔助索引上查找,找到的主鍵值作爲候選記錄,然後到聚集索引上讀取對應記錄,再比較TYPE條件是否滿足。