为什么MYSQL中没有使用索引?

时间:2009-06-15 22:42:17

标签: mysql indexing

非常奇怪如下:

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)

更改'&lt;'到'&gt;'会让它完全不同,为什么?

最后我发现了修复,因为last的默认值为“null”,将此列更改为“not null”会使索引工作。

但是我不知道为什么这会让它变得不同,有什么解释吗?

3 个答案:

答案 0 :(得分:1)

24行不足以让优化者烦恼。你需要用更大的表进行测试。

答案 1 :(得分:0)

  • 首先,这是24行 - 你可能因此而离开;
  • 其次,请尝试将对now()-interval 30 second的引用删除为日期文字。我看到他们扔掉了索引。

这是我还是你有两个完全相同的索引?

答案 2 :(得分:0)

我已经看到MySQL中的查询优化器通过索引选择做了一些奇怪的事情,并且通常找到修复的唯一方法是通过反复试验。有几件事要尝试(不保证他们可能有所帮助):

  • 删除其中一个冗余索引(i_online_*);保留第一列具有更高特异性的那一个(可能是last作为第一列的那个)。
  • 尝试查看lastNOT NULL是否有所不同(使用最小日期而不是null)。
  • 我的第二个Robert Munteanu建议尝试替换now() ...表达式。尝试使用之前设置的变量。

查看表格的整个架构也会有所帮助;也许有一些奇怪的副作用要发现?