2017-12-21 5 views
3

Ich habe eine Abfrage, die etwa 90 Sekunden dauert, obwohl die Tabellen die richtigen Indizes haben sollten. Ich verstehe nicht warum.Single INNER JOIN von zwei gut indizierten Tabellen dauert mehr als eine Minute

Ich benutze MySQL und die Tabellen sind InnoDB.

Dies ist die Abfrage:

SELECT count(*) 
FROM `following_lists` fl INNER JOIN users u 
ON fl.user_uuid = u.user_uuid 
WHERE fl.following_query_id = 1000010 AND u.status <= 2 

Ich erwarte, dass diese Abfrage auf dem Tisch starten following_lists, die WHERE-Bedingung greift etwa 4K Datensätze als pro, diese Datensätze in die Tabelle users durch ihren Primärschlüssel, Scheck beitreten der Wert eines Felds in der Benutzertabelle und gibt die Anzahl der resultierenden Datensätze zurück. Warum dauert es so lange? Könnte es sein, weil die beiden Felder, denen ich die Tabellen beifüge, CHAR (40) sind und keine ganzen Zahlen?

Dies sind die beteiligten Tabellen und deren Indizes:

CREATE TABLE `users` ( 
    `user_uuid` CHAR(40) NOT NULL, 
    `status` TINYINT UNSIGNED NOT NULL, 
    ... 

    PRIMARY KEY (`user_uuid`), 
    ... 
) 

CREATE TABLE `following_lists` ( 
    `following_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    `following_query_id` INT UNSIGNED NOT NULL, 
    `user_uuid` CHAR(40) NOT NULL, 

    PRIMARY KEY (`following_id`), 
    KEY `query_id` (`following_query_id`), 
    KEY `user_uuid` (`user_uuid`) 
) 

Und das ist der Ausgang der erklären Abfrage:

+----+-------------+-------+--------+--------------------+----------+---------+--------------+------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len |  ref  | rows | Extra | 
+----+-------------+-------+--------+--------------------+----------+---------+--------------+------+-------------+ 
| 1 | SIMPLE  | fl | ref | query_id,user_uuid | query_id |  4 | const  | 3718 |    | 
| 1 | SIMPLE  | u  | eq_ref | PRIMARY   | PRIMARY |  160 | fl.user_uuid | 1 | Using index | 
+----+-------------+-------+--------+--------------------+----------+---------+--------------+------+-------------+ 

Weitere Informationen:

  • Die Tabelle following_lists hat ungefähr 25k Reihen, aber nur 3718 haben fl.following_query_id = 1000010.

  • Die Tabelle users hat etwa 160.000 Zeilen, aber nur 3718 sollte in der Verknüpfung ausgewählt werden. Nur 40 Datensätze erfüllen beide Bedingungen fl.following_query_id = 1000010 AND u.status <= 2. Die Abfrage ist langsam, selbst wenn ich die Bedingung AND u.status <= 2 entferne.

+0

wäre ich nicht überrascht, wenn es das CHAR (40) ist. Bei einem ganzzahligen Wert wird 1 Vergleich benötigt; mit diesem CHAR (40) werden bis zu 40 Vergleiche benötigt. Wie viele tatsächlich benötigt werden, hängt von den tatsächlichen Werten in deinem CHAR ab (40), wenn die Werte alle die ersten X Zeichen gleich haben, wird es mindestens so viele nehmen. Wenn ich mich nicht irre, decken die CHAR-Indizes von MySQL auch nicht die gesamte Zeichenfolge ab, sondern nur eine bestimmte Anzahl von führenden Zeichen. – Uueerdo

+1

Verwenden beide Spalten dieselbe Sortierung und denselben Zeichensatz? –

+1

Siehe die akzeptierte Antwort auf diese andere SO Frage. Es könnte Ihnen Hinweise geben, wie Sie die Leistung mit UUID verbessern können. https://StackOverflow.com/questions/2365132/uuid-performance-in-mysql/2365176 –

Antwort

0

"haben die richtigen Indizes" - tot verschenken.

Wenn Sie MyISAM verwenden, tun Sie dies nicht. Wechseln Sie stattdessen zu InnoDB.

Benötigen Sie following_lists.id für alles? Ist (following_query_id, user_uuid) einzigartig? Wenn ja, machen Sie sie zum PRIMARY KEY.

Wenn Sie die oben nicht tun können, ändern

KEY `query_id` (`following_query_id`) 

zu

INDEX(following_query_id, user_uuid) 

UUIDs ineffizient sind schrecklich, vor allem, wenn unnötig utf8mb4 erklärt, oder CHAR mit einer größeren als notwendigen Größe. Wechseln Sie zu CHAR(36) CHARACTER SET ascii. (Beachten Sie die "160" in der `EXPLAIN deutlich schrumpfen.)

Mehr darüber, warum UUIDs für die Leistung schlecht sind: http://mysql.rjweb.org/doc.php/uuid

Wie viel RAM haben Sie? Was ist die Einstellung für innodb_buffer_pool_size? (Klingt wie es ist zu niedrig.

)

Mehr auf Indizierung: http://mysql.rjweb.org/doc.php/index_cookbook_mysql