2009-06-15 17 views
1

Sehr seltsam wie folgt:Warum Index hier in MYSQL nicht verwendet?

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) 

Für diejenigen, die wegen der Tabellengröße ist es sagen:

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) 

Hier sind einige weitere Hinweise:

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 '<' auf ' > wird es ganz anders machen, warum?

Endlich fand ich das Update, es ist wegen last hat einen Standardwert "null", ändern Sie diese Spalte auf "nicht null" wird den Index arbeiten.

Aber ich habe keine Ahnung, warum das es anders machen kann, irgendwelche Erklärungen?

Antwort

1

24 Zeilen reichen dem Optimierer nicht aus. Sie müssen mit einer größeren Tabelle testen.

+0

Siehe mein Update am Ende. – omg

0
  • Zunächst einmal sind es 24 Zeilen - Sie könnten gerade deswegen aus sein;
  • Zweitens, versuchen Sie, den Verweis auf now()-interval 30 second zu einem Datum Literal zu entfernen. Ich habe gesehen, wie sie Indizes abwerfen.

Ist mir dies oder haben Sie zwei Indizes, die genau die gleichen sind?

+0

Muss ein anderer Grund sein, ich habe es mit 150 Datensätzen gefüllt, immer noch nicht mit Index. – omg

+0

Sogar 150 ist niedrig genug, dass der Optimierer nicht stören könnte. Sie müssen mit ein paar tausend Zeilen testen. Auch der zweite Index hat die Spalten um den falschen Weg. – staticsan

+0

Dies sollte nicht der Grund sein, ich habe oft scheinen, dass Index verwendet wird, auch Tabellengröße ist nicht mehr als 100 Datensätze. – omg

0

Ich habe gesehen, dass der Abfrageoptimierer in MySQL einige seltsame Dinge mit der Indexselektion gemacht hat, und oft war der einzige Weg, eine Korrektur zu finden, Versuch und Irrtum. Ein paar Dinge zu versuchen (ohne jegliche Garantie, dass sie helfen könnten):

  • Entfernen Sie einen der redundanten Indizes (i_online_*); behalte den, wo die erste Spalte eine höhere Spezifität hat (wahrscheinlich die mit last als erste Spalte).
  • Versuchen NOT NULL macht einen Unterschied, ob die Herstellung last Spalt zu sehen (mit einem Mindest Datum statt null).
  • Ich zweiten Robert Munteanu Vorschlag des Versuches, die now() ... Ausdruck zu ersetzen. Versuchen Sie, eine Variable zu verwenden, die Sie zuvor festgelegt haben.

Es würde auch helfen, das gesamte Schema Ihrer Tabelle zu sehen; Vielleicht gibt es einige seltsame Nebenwirkungen zu entdecken?

+0

Ich habe meinen Beitrag aktualisiert, einige wichtige Hinweise gefunden :) – omg

+0

Ich habe es gefunden, weil letzter hat einen Standardwert null, aber weiß nicht warum. – omg

+0

Manchmal werden Indizes für Spalten, die NULL-Werte enthalten, vom Abfrageplan-Scheduler nicht verwendet, insbesondere für Bereichsabfragen (bei Vergleichen mit weniger als oder größer als bei Vergleichen).Auch, wenn meine Kommentare geholfen haben, zögern Sie nicht, diese Frage als beantwortet zu markieren ;-) –

Verwandte Themen