tags:

views:

480

answers:

3

Very odd as follows:

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)

For those who say it's because of table size:

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)

Here are some more clues:

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)

Change '<' to '>' will make it totally different,why?

At last I found the fix,it's because of last has a default value "null",change this column to "not null" will make index work.

But I've no idea why this can make it different,any explanations?

+1  A: 

24 rows isn't enough for the optimizer to bother with. You need to test with a larger table.

le dorfier
See my update in the end.
Shore
A: 
  • First of all, it's 24 rows - you might be off just because of that;
  • Second of all, try removing the reference to now()-interval 30 second to a date literal. I've seen them throw off indexes.


Is this me or do you have 2 indexes which are exactly the same?

Robert Munteanu
Must be some other reason,I populated it with 150 records,still not using index.
Shore
Even 150 is low enough that the optimizier mightn't bother. You need to test with a few thousand rows. Also, your second index has the columns around the wrong way.
staticsan
This should not be the reason,I've seem many times that index is used even table size is no more than 100 records.
Shore
A: 

I have seen the query optimizer in MySQL do some strange things with index selection, and often the only way to find a fix was by trial and error. A couple things to try (without any guarantee that they might help):

  • Remove one of the redundant indexes (i_online_*); keep the one where the first column has higher specificity (probably the one with last as the first column).
  • Try to see whether making the last column NOT NULL makes a difference (use a minimum date instead of null).
  • I second Robert Munteanu's suggestion of trying to replace the now() ... expression. Try to use a variable there that you have set before.

It would also help to see the entire schema of your table; maybe there are some weird side-effects to spot?

Thomas Jung
I've updated my post,found some important clue:)
Shore
I've found it's because of last has a default value null,but don't know why.
Shore
Sometimes, indexes over columns containing NULL values are not being used by the query plan scheduler, especially for range queries (involving less than or greater than comparisons). Also, if my comments helped, don't hesitate to mark this question as answered ;-)
Thomas Jung
... because of the NULL value issue, I recommended trying to make the LAST column NOT NULL
Thomas Jung