почему индекс не используется здесь в MYSQL? - PullRequest
1 голос
/ 16 июня 2009

Очень странно так:

mysql> explain select *from online where last < now()-interval 30 second and type=1;
+----+-------------+--------+------+---------------------------------------+------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys                         | key  | key_len | ref  | rows | Extra       |
+----+-------------+--------+------+---------------------------------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | online | ALL  | i_online_type_last,i_online_last_type | NULL | NULL    | NULL |   24 | Using where |
+----+-------------+--------+------+---------------------------------------+------+---------+------+------+-------------+

mysql> explain select *from online where last < '2009-06-16 06:48:33' and type=1;
+----+-------------+--------+------+---------------------------------------+------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys                         | key  | key_len | ref  | rows | Extra       |
+----+-------------+--------+------+---------------------------------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | online | ALL  | i_online_type_last,i_online_last_type | NULL | NULL    | NULL |  120 | Using where |
+----+-------------+--------+------+---------------------------------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)


mysql> show index from online;
+--------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table  | Non_unique | Key_name           | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| online |          0 | PRIMARY            |            1 | id          | A         |          24 |     NULL | NULL   |      | BTREE      |         |
| online |          0 | account_id         |            1 | account_id  | A         |          24 |     NULL | NULL   |      | BTREE      |         |
| online |          1 | i_online_type_last |            1 | last        | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |
| online |          1 | i_online_type_last |            2 | type        | A         |           2 |     NULL | NULL   |      | BTREE      |         |
| online |          1 | i_online_last_type |            1 | last        | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |
| online |          1 | i_online_last_type |            2 | type        | A         |           2 |     NULL | NULL   |      | BTREE      |         |
+--------+------------+--------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
6 rows in set (0.00 sec)

Для тех, кто говорит, что это из-за размера стола:

mysql> explain select *from users where email='test@gmail.com';
+----+-------------+-------+-------+---------------+---------------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key           | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+-------+------+-------+
|  1 | SIMPLE      | users | const | u_users_email | u_users_email | 386     | const |    1 |       |
+----+-------------+-------+-------+---------------+---------------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql> select count(*) from users;
+----------+
| count(*) |
+----------+
|       24 |
+----------+
1 row in set (0.00 sec)

Вот еще несколько подсказок:

mysql> explain select * from online where `last` > '2009-06-16 06:48:33' and type in (1,2);
+----+-------------+--------+-------+--------------------+--------------------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys      | key                | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+--------------------+--------------------+---------+------+------+-------------+
|  1 | SIMPLE      | online | range | i_online_type_last | i_online_type_last | 13      | NULL |    2 | Using where |
+----+-------------+--------+-------+--------------------+--------------------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> explain select * from online where `last` < '2009-06-16 06:48:33' and type in (1,2);
+----+-------------+--------+------+--------------------+------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys      | key  | key_len | ref  | rows | Extra       |
+----+-------------+--------+------+--------------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | online | ALL  | i_online_type_last | NULL | NULL    | NULL |  120 | Using where |
+----+-------------+--------+------+--------------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

Изменение '<' на '>' сделает его совершенно другим, почему?

Наконец-то я нашел исправление, потому что last имеет значение по умолчанию "null", изменение этого столбца на "not null" приведет к работе индекса.

Но я понятия не имею, почему это может сделать его другим, какие-либо объяснения?

Ответы [ 3 ]

1 голос
/ 16 июня 2009

24 строки недостаточно для оптимизатора, чтобы беспокоиться. Вам нужно проверить с большим столом.

0 голосов
/ 16 июня 2009

Я видел, как оптимизатор запросов в MySQL делал странные вещи с выбором индекса, и часто единственным способом найти исправление был метод проб и ошибок. Несколько вещей, чтобы попробовать (без какой-либо гарантии, что они могут помочь):

  • Удалить один из избыточных индексов (i_online_*); оставьте тот, где первый столбец имеет более высокую специфичность (вероятно, тот, в котором last в качестве первого столбца).
  • Попробуйте выяснить, имеет ли значение столбец last NOT NULL (используйте минимальная дата вместо null).
  • Я второе предложение Роберта Мунтяну о попытке заменить выражение now() .... Попробуйте использовать переменную, которую вы установили ранее.

Это также поможет увидеть всю схему вашей таблицы; может быть, есть какие-то странные побочные эффекты, которые можно обнаружить?

0 голосов
/ 16 июня 2009
  • Во-первых, это 24 строки - возможно, вы просто отключились;
  • Во-вторых, попробуйте удалить ссылку на now()-interval 30 second на литерал даты. Я видел, как они сбрасывали индексы.

Это я или у вас 2 одинаковых индекса?

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