2009-07-02 5 views
3

Eine bestimmte UPDATE Abfrage auf unserer Website läuft manchmal sehr langsam und untersucht viel mehr Zeilen als nötig. Es wird nach dem Primärschlüssel gefiltert, daher würde ich erwarten, dass MySQL immer nur eine Zeile untersuchen müsste.MySQL UPDATE Abfrage nach Primärschlüssel ist manchmal extrem langsam

Hier einige Beispiele aus dem MySQL-Slow-Query-Log:

# Time: 090702 12:59:06 
# [email protected]: XXX[XXX] @ XXX [XXX] 
# Query_time: 21 Lock_time: 0 Rows_sent: 0 Rows_examined: 500500 
SET timestamp=1246532346; 
UPDATE `folders` SET `folder_id` = '1705641', `updated_at` = now() WHERE `folders`.`id` = '1682995'; 
# Time: 090702 14:13:44 
# [email protected]: XXX[XXX] @ XXX [XXX] 
# Query_time: 17 Lock_time: 0 Rows_sent: 0 Rows_examined: 16816745 
SET timestamp=1246536824; 
UPDATE `folders` SET `folder_id` = '417997', `updated_at` = now() WHERE `folders`.`id` = '1705956'; 
# Time: 090702 14:15:42 
# [email protected]: XXX[XXX] @ XXX [XXX] 
# Query_time: 13 Lock_time: 0 Rows_sent: 0 Rows_examined: 16816719 
SET timestamp=1246536942; 
UPDATE `folders` SET `folder_id` = '1706267', `updated_at` = now() WHERE `folders`.`id` = '1705956'; 
# Time: 090702 16:07:43 
# [email protected]: XXX[XXX] @ XXX [XXX] 
# Query_time: 499 Lock_time: 0 Rows_sent: 0 Rows_examined: 88668449 
SET timestamp=1246543663; 
UPDATE `folders` SET `folder_id` = '1707407', `updated_at` = now() WHERE `folders`.`id` = '1706992'; 

Die Abfrage als die häufigen ausgeführt wird, aber so ist es nicht immer dieses Verhalten aussetzen. Auch wenn ich die gleichen Abfragen manuell ausführen, laufen sie gut und kehren sofort zurück.

Ich überprüfte auch die Tabelle und soweit ich es sollte in Ordnung sein sehen:

mysql> describe folders; 
+------------------+-----------------------+------+-----+---------------------+----------------+ 
| Field   | Type     | Null | Key | Default    | Extra   | 
+------------------+-----------------------+------+-----+---------------------+----------------+ 
| id    | mediumint(8) unsigned | NO | PRI | NULL    | auto_increment | 
| user_id   | mediumint(8) unsigned | NO | MUL | NULL    |    | 
| folder_id  | mediumint(8) unsigned | YES | MUL | NULL    |    | 
| created_at  | timestamp    | NO |  | CURRENT_TIMESTAMP |    | 
| updated_at  | timestamp    | NO |  | 0000-00-00 00:00:00 |    | 
| modified_at  | timestamp    | NO |  | 0000-00-00 00:00:00 |    | 
| name    | varchar(255)   | NO |  | NULL    |    | 
| guest_permission | tinyint(3) unsigned | NO |  | 1     |    | 
+------------------+-----------------------+------+-----+---------------------+----------------+ 
8 rows in set (0.00 sec) 

mysql> show index from folders; 
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| folders |   0 | PRIMARY |   1 | id   | A   |  760318 |  NULL | NULL |  | BTREE  |   | 
| folders |   1 | user_id |   1 | user_id  | A   |  69119 |  NULL | NULL |  | BTREE  |   | 
| folders |   1 | folder_id |   1 | folder_id | A   |  380159 |  NULL | NULL | YES | BTREE  |   | 
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
3 rows in set (0.00 sec) 

Eine andere Sache ist, dass der MySQL-Server manchmal sperrt und stoppt die Annahme von Verbindungen, und jedesmal, wenn dies geschieht, ich in der Regel finden Sie eine dieser langsamen Abfragen in der Protokolldatei unmittelbar vor dem Fehler. Ich kann keine relevanten Fehlermeldungen in anderen Logfiles sehen, aber ein MySQL-Neustart macht es wieder ansprechbar.

Hat jemand eine Idee, was ist los, oder welche Dinge könnte ich überprüfen, um das Problem einzugrenzen?

EDIT: Wir verwenden MySQL 5.0.51a auf einem dedizierten Server, und derzeit 6 Webserver mit PHP 5.2.6 und Verbindung über PDO mit dem MySQL-Server. Auf allen Servern läuft Debian Lenny. Die langsame Abfrage erfolgt auf allen Webservern.

EDIT: Hier ist ein für ein verwandtes Abfrage ERKLÄREN, mit und ohne Anführungszeichen:

mysql> explain SELECT * FROM `folders` WHERE `folders`.`id` = '1682995'; 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 
| 1 | SIMPLE  | folders | const | PRIMARY  | PRIMARY | 3  | const | 1 |  | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 
1 row in set (0.00 sec) 

mysql> explain SELECT * FROM `folders` WHERE `folders`.`id` = 1682995; 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 
| 1 | SIMPLE  | folders | const | PRIMARY  | PRIMARY | 3  | const | 1 |  | 
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 
1 row in set (0.00 sec) 
+0

Das ist wirklich interessant, ich würde gerne wissen, warum es das auch tut. Haben Sie EXPLAIN SELECT * FROM 'Ordner' versucht? WHERE' id' = etwas? –

Antwort

1

Dumm mich. Ich habe vergessen, dass es einige Trigger auf der folders Tabelle gab, und natürlich war es eine Abfrage in einem dieser Trigger, die meine Probleme verursacht haben ...

Es gibt eine zusätzliche Tabelle tree, die die Verknüpfungen zwischen den Ordnern verwaltet, und die Trigger aktualisieren diese Verknüpfungen, wenn ein Ordner in der Hierarchie gelöscht oder verschoben wird. Im Trigger UPDATE müssen alle vorhandenen Verweise auf den Ordner gelöscht werden, bevor die neuen Verweise hinzugefügt werden. Die entsprechende DELETE Abfrage begann wie folgt:

DELETE FROM `tree` 
    WHERE `folder_id` IN (
    SELECT `folder_id` FROM `children` 
) 
    AND ... 

children eine temporäre Tabelle ist, wo ich die Ordner-ID der zuvor speichere ich brauche. Jetzt aus irgendeinem Grunde MySQL kann diese Abfrage nicht optimieren, aber wenn ich ein RIGHT JOIN stattdessen funktioniert es völlig in Ordnung:

DELETE `tree`.* FROM `tree` 
    RIGHT JOIN children USING (folder_id) 
    WHERE ... 

Da ich diese Abfrage MySQL langsam Abfrageprotokoll wohlig leer geändert haben bleibt, und wir habe keine MySQL-Sperren erlebt.

1

Das ist seltsam, aber meine Vermutung ist es könnte sein, weil Ihre ID-Feld int ist aber Sie vorbei eine Zeichenfolge (zitiert). Versuchen Sie nicht, eine Zeichenfolge zu verwenden und sehen Sie, ob es hilft.

Um herauszufinden, was genau los ist, ändern Sie die Abfrage zu einem SELECT mit der gleichen WHERE-Klausel und führen Sie es durch EXPLAIN. Gefällt mir:

EXPLAIN SELECT * FROM `folders` WHERE `folders`.`id` = '1682995'; 
EXPLAIN SELECT * FROM `folders` WHERE `folders`.`id` = 1682995; 

Sehen Sie, ob es einen Unterschied gibt.

More info on EXPLAIN.

+0

Kein Unterschied. Wenn das wirklich der Grund wäre, würde ich erwarten, dass die Abfrage IMMER so langsam ist. Aber danke für die Hilfe! – toupeira