2012-03-09 58 views
12

我命名 '測試' 具有兩列一個簡單的MySQL表:的MySQL不使用索引的ORDER BY

  1. 自動遞增INT列稱爲 'id'
  2. VARCHAR(3000)列被稱爲「textcol '

我根據'textcol'列在表格中創建索引。但是,ORDER BY查詢似乎沒有使用索引,即在textcol上的ORDER BY的簡單查詢上的EXPLAIN語句在其輸出的Key列中顯示NULL,並且也使用filesort。

任何進行更改以幫助通過查詢爲ORDER使用索引的指針都對我很有用。

如通過「的MySQL --version」命令給出

MySQL版本:使用的ReadLine

的MySQL版14.14 DISTRIB 58年5月1日,對於Debian的Linux-GNU(x86_64的)6.2

mysql> CREATE TABLE test (id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), textcol VARCHAR(3000)); 
Query OK, 0 rows affected (0.05 sec) 

mysql> DESCRIBE test; 
+---------+---------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+---------+---------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| textcol | varchar(3000) | YES |  | NULL |    | 
+---------+---------------+------+-----+---------+----------------+ 
2 rows in set (0.00 sec) 

mysql> CREATE INDEX textcolindex ON test (textcol); 
Query OK, 0 rows affected, 2 warnings (0.06 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> SHOW INDEX FROM test; 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| test |   0 | PRIMARY  |   1 | id   | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| test |   1 | textcolindex |   1 | textcol  | A   |  NULL |  1000 | NULL | YES | BTREE  |   | 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
2 rows in set (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test1'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test2'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test3'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test4'); 
Query OK, 1 row affected (0.00 sec) 


mysql> EXPLAIN SELECT * FROM test ORDER BY textcol; 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| 1 | SIMPLE  | test | ALL | NULL   | NULL | NULL | NULL | 4 | Using filesort | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
1 row in set (0.00 sec) 

mysql> EXPLAIN SELECT * FROM test ORDER BY id; 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| 1 | SIMPLE  | test | ALL | NULL   | NULL | NULL | NULL | 4 | Using filesort | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
1 row in set (0.00 sec) 
+0

你是否繼續在表中看到很多數據?解釋並沒有告訴你這個查詢總是會做什麼,只是這個查詢在這個時候會做什麼。 – 2012-03-09 21:54:14

+0

我將textcol列的大小更改爲10個字節,並插入了30000個新行。 SELECT *中的ORDER BY仍然不使用索引。但是,我只注意到SELECT COUNT(*)語句使用索引。任何想法爲什麼發生這種情況? – Kowshik 2012-03-09 22:12:53

回答

9

由於它必須加載整個表來回答查詢和排序4個元素是便宜的,查詢優化器可能只是避免觸摸索引。它是否仍然發生在更大的表上?

請注意,varchar(3000)列能夠' t是覆蓋索引,因爲MySQL不會在索引中包含超過varchar的前768個字節。

如果您希望查詢只讀取索引,那麼索引必須包含您在其中的每個列SELECT。在innodb上,一旦你使textcol足夠小,它應該開始爲你的雙列表工作;對MyISAM數據,你需要把自己包含在主鍵列,就像CREATE INDEX textcolindex ON test (textcol,id);

+0

我將textcol列的大小更改爲10個字節,並插入了30000個新行。 SELECT *中的ORDER BY仍然不使用索引。但是,我只注意到SELECT COUNT(*)語句使用索引。任何想法爲什麼發生這種情況? – Kowshik 2012-03-09 22:14:34

+1

爲了說明起見,索引對於MyISAM是1000字節限制,對於InnoDB是767,對於3000 varchar字段來說是很害羞的。實際上,MySQL將使用一個索引前綴,它可以用來幫助查找(例如,WHERE子句),但是它不能用於排序,因爲它是不完整的:http://dev.mysql.com/doc/refman /5.0/en/order-by-optimization.html – 2012-03-09 22:22:39

+1

@Khowshik,如果沒有「覆蓋」索引,MySQL將不得不做30,000次尋找來利用索引。 filesort仍然比30,000個搜索更容易。嘗試'選擇textcol ORDER BY textcol'。 – 2012-03-09 22:29:04

5

訂購一些有用的文章優化:

http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/

http://opsmonkey.blogspot.co.uk/2009/03/mysql-query-optimization-for-order-by.html

在很大程度上討論,保留下來的varchar到767,並添加一個密鑰的訂單:

CREATE TABLE test (
id INTEGER NOT NULL AUTO_INCREMENT, 
textcol VARCHAR(767), 
PRIMARY KEY(id), 
KEY orderby (`textcol`) 
); 

爲了避免filesorts如果增加額外 'WHERE' 參數,使用多列索引延長 '的OrderBy' 索引關鍵字:

CREATE TABLE test (
id INTEGER NOT NULL AUTO_INCREMENT, 
tom INT(11) NOT NULL DEFAULT 0, 
gerry INT(11) NOT NULL DEFAULT 0, 
textcol VARCHAR(767), 
PRIMARY KEY(id), 
KEY orderby (`tom`,`gerry`, `textcol`) 
); 

另外:

INSERT INTO test (tom, gerry, textcol) VALUES (1,2,'test4'); 
INSERT INTO test (tom, gerry, textcol) VALUES (1,2,'test2'); 
EXPLAIN SELECT id, textcol FROM test WHERE tom = 1 AND gerry =2 ORDER BY textcol; 

額外:「使用其中;使用索引'

+0

感謝您的鏈接。雖然很老,但他們很有幫助 – 2017-01-12 09:26:55

1

我得到了同樣的問題。 MySQL是愚蠢的。 fyi:我有一張擁有5億多記錄的桌子。我想:

select * from table order by tid limit 10000000, 10; 

tid是表中的主鍵,並自動地被mysql索引。

這花了很長時間,我取消了查詢。那麼我讓MySQL「解釋」查詢並認識到它不會使用主鍵的索引。在閱讀了許多從MySQL的文檔後,我試圖強制MySQL通過「USE INDEX(...)」使用索引,DIS也沒有工作。然後我認識到,mysql似乎總是將where子句與order by子句關聯起來。所以我試圖用觸及索引的條件來擴展where子句。我結束了:

select * from table use index (PRIMARY) where tid > 0 order by tid limit 10000000, 10; 

其中TID是在表的主鍵並且是從1開始

這個工作後,我讓MySQL的解釋查詢到我的自動增量值。注意:查詢只需要4秒鐘。

+0

謝謝你發佈這個。這可能有一天會派上用場 – 2017-01-05 15:38:15