多列索引的select * where * order by * 查詢條件索引很難建立,需要不斷調試,最後找出規則:
三原則:
1. 將經常要查詢的字段放到多列索引的前面
2. 將要進行等值查詢的字段放到多列索引前面
3. order by field的列放到多列索引的最後
以下是測試
先來一張表:
CREATE TABLE IF NOT EXISTS `article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uid` int(10) unsigned NOT NULL,
`category_id` int(10) unsigned NOT NULL,
`views` int(10) unsigned NOT NULL,
`comments` int(10) unsigned NOT NULL,
`title` varbinary(255) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`)
);
再插幾條數據:
INSERT INTO `article`
(`uid`, `category_id`, `views`, `comments`, `title`, `content`) VALUES
(1, 1, 1, 1, '1', '1'),
(2, 2, 2, 2, '2', '2'),
(1, 1, 3, 3, '3', '3');
需求:
查詢category_id爲1且comments大於1的情況下,views最多的uid。
先查查試試看:
EXPLAIN SELECT uid FROM `article` WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
看看部分輸出結果:
很顯然,type是ALL,即最壞的情況。Extra裏還出現了Using filesort,也是最壞的情況。優
化是必須的。
嗯,那麼最簡單的解決方案就是加索引了。好,我們來試一試。查詢的條件裏即where之
後共使用了category_id,comments,views三個字段。那麼來一個聯合索引是最簡單的了。
ALTER TABLE `article` ADD INDEX x ( `category_id` , `comments`, `views` );
結果有了一定好轉,但仍然很糟糕:
type變成了range,這是可以忍受的。但是extra裏使用Using filesort仍是無法接受的。
但是我們已經建立了索引,爲啥沒用呢?
這是因爲按照BTree索引的工作原理,先排序category_id,如果遇到相同的category_id則再
排序comments,如果遇到相同的comments則再排序views。當comments字段在聯合索引
裏處於中間位置時,因爲comments > 1條件是一個範圍值(所謂range),MySQL無法利用
索引再對後面的views部分進行檢索,即range類型查詢字段後面的索引無效。
那麼我們需要拋棄comments,刪除舊索引DROP INDEX x ON article;
然後建立新索引:ALTER TABLE `article` ADD INDEX y ( `category_id` , `views` ) ;
接着再運行查詢:
可以看到,type 變爲了ref,Extra中的Using filesort也消失了,結果非常理想。
http://hi.baidu.com/jqxw4444/item/e3cf91393fa89f9bb80c0388