MySQL не использует индекс для ORDER BY - PullRequest
13 голосов
/ 10 марта 2012

У меня есть простая таблица MySQL с именем 'test' с двумя столбцами:

  1. Автоинкрементный столбец int с именем 'id'
  2. Varchar (3000) столбец под названием «textcol»

Я создаю индекс в таблице на основе столбца 'textcol'. Однако запрос ORDER BY, похоже, не использует индекс, то есть оператор EXPLAIN для простого запроса с ORDER BY для textcol показывает NULL в столбце Key в своих выходных данных, а также использует filesort.

Мне пригодятся любые указатели для внесения изменений, которые помогут использовать индекс для ORDER по запросу.

Версия MySQL, заданная командой "mysql --version":

mysql Ver 14.14 Distrib 5.1.58, для debian-linux-gnu (x86_64) с использованием readline 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)

Ответы [ 3 ]

9 голосов
/ 10 марта 2012

Поскольку для ответа на запрос приходится загружать всю таблицу, а сортировка 4 элементов обходится дешево, оптимизатор запросов может просто не касаться индекса. Это все еще происходит с большими таблицами?

Обратите внимание, что столбец varchar (3000) не может быть индексом покрытия, поскольку MySQL не будет включать в индекс больше, чем первые 768 или около того байтов varchar.

Если вы хотите, чтобы запрос считывал только индекс, в индексе должен быть каждый столбец, для которого вы SELECT хотите найти. На innodb это должно начать работать для вашей таблицы из двух столбцов, как только вы сделаете textcol достаточно маленьким; в MyISAM вам нужно будет включить столбец первичного ключа, например CREATE INDEX textcolindex ON test (textcol,id);

5 голосов
/ 02 мая 2012

Несколько полезных статей по оптимизации ORDER BY:

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;

Дополнительно: «Использование где; Использование индекса '

3 голосов
/ 28 июня 2016

У меня такая же проблема.MySQL тупойК вашему сведению: у меня есть таблица с более чем 500 000 000 записей.Я хотел:

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 секунды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...