Es ist eine typische Users
Tabelle, die Felder enthält: id (primary)
, application_id
, login
, phone
usw. (application_id
- selektives Feld)MySQL verwendet falschen Index. Warum?
Es gibt nur wenige Indizes sind:
index_users_on_application_id,
unique_index_users_on_application_id_and_login
unique_index_users_on_application_id_and_phone
Die Abfrage selbst ist sehr einfach:
SELECT `users`.*
FROM `users`
WHERE `users`.`application_id` = 1234
LIMIT 10 OFFSET 0;
Der schwierige Teil ist, dass diese Abfrage einen von zwei eindeutigen Indizes verwendet (unique_index_users_on_application_id_and_login
zum Beispiel) und gibt dann eine Liste der Benutzer zurück, sortiert nach login
. Aber ich brauche sie sortiert nach id
.
Zu diesem Zweck habe ich die Abfrage aktualisiert:
SELECT `users`.*
FROM `users`
WHERE `users`.`application_id` = 1234
ORDER BY id
LIMIT 10 OFFSET 0;
Nun, jetzt zeigt erklären, dass MySQL PRIMARY
Schlüssel anstelle von irgendwelchen Indizes beginnt mit. Aber wie ist das passiert? Wenn index_users_on_application_id
tatsächlich zwei Felder enthalten sollte: [application_id, id] (InnoDB), so dass der Index für die Abfrage perfekt ist, aber MySQL beschließt, einen anderen zu wählen.
Wenn ich sage IGNORE INDEX(PRIMARY)
, beginnt MySQL mit unique_index_users_on_application_id_and_login
, immer noch den richtigen Index zu ignorieren. Gleiches Ergebnis, wenn ORDER BY id+0
.
Ich habe auch versucht, ORDER BY application_id, id
um sicherzustellen, dass der Index am besten passt, wählt MySQL immer noch falsche Index.
Irgendwelche Ideen, warum passiert es und wie kann ich sicherstellen, dass MySQL den richtigen Index verwendet, ohne explizit USE INDEX(index_users_on_application_id)
zu sagen?
Liste von Indizes für Users
Tabelle:
mysql> show indexes from users;
+-------+------------+-----------------------------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-----------------------------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| users | 0 | PRIMARY | 1 | id | A | 21893 | NULL | NULL | | BTREE | | |
| users | 0 | index_users_on_confirmation_token | 1 | confirmation_token | A | 28 | NULL | NULL | YES | BTREE | | |
| users | 0 | index_users_on_reset_password_token | 1 | reset_password_token | A | 50 | NULL | NULL | YES | BTREE | | |
| users | 0 | index_users_on_application_id_and_external_user_id | 1 | application_id | A | 32 | NULL | NULL | YES | BTREE | | |
| users | 0 | index_users_on_application_id_and_external_user_id | 2 | external_user_id | A | 995 | NULL | NULL | YES | BTREE | | |
| users | 0 | index_users_on_application_id_and_login | 1 | application_id | A | 30 | NULL | NULL | YES | BTREE | | |
| users | 0 | index_users_on_application_id_and_login | 2 | login | A | 21893 | NULL | NULL | YES | BTREE | | |
| users | 1 | users_account_id_fk | 1 | account_id | A | 44 | NULL | NULL | | BTREE | | |
| users | 1 | users_blob_id_fk | 1 | blob_id | A | 118 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_remember_token | 1 | remember_token | A | 8 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id | 1 | application_id | A | 32 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_facebook_id | 1 | application_id | A | 32 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_facebook_id | 2 | facebook_id | A | 3127 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_twitter_digits_id | 1 | application_id | A | 32 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_twitter_digits_id | 2 | twitter_digits_id | A | 138 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_email | 1 | application_id | A | 32 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_email | 2 | email | A | 2189 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_full_name | 1 | application_id | A | 32 | NULL | NULL | YES | BTREE | | |
| users | 1 | index_users_on_application_id_and_full_name | 2 | full_name | A | 5473 | NULL | NULL | YES | BTREE | | |
+-------+------------+-----------------------------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
19 rows in set (0.01 sec)
Beispiel ERKLäREN:
mysql> EXPLAIN SELECT `users`.* FROM `users` WHERE `users`.`application_id` = 56374 ORDER BY id asc LIMIT 1 OFFSET 0;
+----+-------------+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------+---------+-------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------+---------+-------+------+-----------------------------+
| 1 | SIMPLE | users | ref | index_users_on_application_id_and_external_user_id,index_users_on_application_id_and_login,index_users_on_application_id,index_users_on_application_id_and_facebook_id,index_users_on_application_id_and_twitter_digits_id,index_users_on_application_id_and_email,index_users_on_application_id_and_full_name | index_users_on_application_id_and_external_user_id | 5 | const | 1 | Using where; Using filesort |
+----+-------------+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------+---------+-------+------+-----------------------------+
1 row in set (0.00 sec)
Das Problem selbst ist, dass falscher Index mit verursacht Abfragen wie die (mit einem Limit von 100 statt 1) MINUTEN durchgeführt werden, während es bei einem korrekten Index um Sekundenbruchteile geht.
Profilierung:
SET PROFILING = 1; SELECT `users`.* FROM `users` WHERE `users`.`application_id` = 56374 ORDER BY id asc LIMIT 1 OFFSET 0; SHOW PROFILE FOR QUERY 1; SET PROFILING = 0;
Query OK, 0 rows affected (0.00 sec)
+----------+----------+-----------------+-------+-------+----------------------------------------------------------------------------------------------------------------------------------+----------------------+-------+---------+---------------------+---------------------+---------------------+------------------+-------------+------------+---------+----------------------+------------------------+---------------------+--------------------+---------------------+----------------------+-------------------+------------+----------------+-------------+---------------------------------------------------------------------------------------+-------------------+-------------------------+--------------------------------------------------+----------------+
-- fields list --
+----------+----------+-----------------+-------+-------+----------------------------------------------------------------------------------------------------------------------------------+----------------------+-------+---------+---------------------+---------------------+---------------------+------------------+-------------+------------+---------+----------------------+------------------------+---------------------+--------------------+---------------------+----------------------+-------------------+------------+----------------+-------------+---------------------------------------------------------------------------------------+-------------------+-------------------------+--------------------------------------------------+----------------+
| 27265241 | NULL | Some Username | NULL | 9777 | SomeHash | AnotherHash | NULL | NULL | 2017-04-12 15:53:32 | 2017-09-21 13:39:51 | 2017-09-24 19:19:06 | 1234 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 2017-07-05 10:59:59 | NULL | NULL | 12345 | NULL | NULL | something_else | NULL | 1 | another_hash | 54321 |
+----------+----------+-----------------+-------+-------+----------------------------------------------------------------------------------------------------------------------------------+----------------------+-------+---------+---------------------+---------------------+---------------------+------------------+-------------+------------+---------+----------------------+------------------------+---------------------+--------------------+---------------------+----------------------+-------------------+------------+----------------+-------------+---------------------------------------------------------------------------------------+-------------------+-------------------------+--------------------------------------------------+----------------+
1 row in set (1 min 14.43 sec)
+--------------------------------+-----------+
| Status | Duration |
+--------------------------------+-----------+
| starting | 0.000068 |
| Waiting for query cache lock | 0.000025 |
| init | 0.000025 |
| checking query cache for query | 0.000047 |
| checking permissions | 0.000026 |
| Opening tables | 0.000031 |
| After opening tables | 0.000025 |
| System lock | 0.000025 |
| Table lock | 0.000026 |
| Waiting for query cache lock | 0.000037 |
| init | 0.000046 |
| optimizing | 0.000032 |
| statistics | 0.000225 |
| preparing | 0.000042 |
| executing | 0.000025 |
| Sorting result | 0.000057 |
| Sending data | 42.952100 |
| end | 0.000070 |
| query end | 0.000027 |
| closing tables | 0.000025 |
| Unlocking tables | 0.000028 |
| freeing items | 0.000028 |
| updating status | 0.000039 |
| cleaning up | 0.000025 |
+--------------------------------+-----------+
24 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Es ist sehr schwer, Ihre Frage zu folgen - können Sie bitte die volle DDL für diese Tabelle veröffentlichen, einschließlich Indizes und den Abfrageplan zeigen? –
Bitte veröffentlichen Sie das Ergebnis von 'show Indizes von Benutzern;' – fancyPants
hinzugefügt beide Liste von Indizes und erklären Beispiel – nattfodd