2009-06-15 52 views
1

非常奇怪如下:为什么在MYSQL中这里不使用索引?

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='[email protected]'; 
+----+-------------+-------+-------+---------------+---------------+---------+-------+------+-------+ 
| 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”会使索引起作用。

但我不知道为什么这可以使它不同,任何解释?

回答

1

对于优化器来说,24行是不够的。您需要使用更大的表格进行测试。

+0

最后看我的更新。 – omg 2009-06-15 22:58:06

0
  • 首先,它是24行 - 你可能会因此而关闭;
  • 其次,尝试删除对日期文字now()-interval 30 second的引用。我看到他们扔掉索引。

这是我还是你有2个指标,其是完全一样的?

+0

必须是其他一些原因,我用150条记录填充它,仍然没有使用索引。 – omg 2009-06-15 22:49:27

+0

即使150也足够低,优化者可能不会打扰。你需要测试几千行。此外,你的第二个索引有错误的方式列。 – staticsan 2009-06-15 22:52:04

0

我看到MySQL中的查询优化器用索引选择做了一些奇怪的事情,并且通常只有通过试验和错误才能找到修复。一对夫妇可以尝试(不作任何保证,他们可能会帮助):

  • 删除冗余的指标之一(i_online_*);保留第一列具有更高特异性的那个(可能是第一列为last的那个)。
  • 尝试看看是否作出lastNOT NULL有差别(使用最低日期,而不是null)。
  • 我第二次罗伯特蒙代亚努的建议,试图取代now() ...表达式。尝试使用之前设置的变量。

它也将有助于查看您的表的整个架构;也许有一些奇怪的副作用要发现?