2009-07-02 11 views
3

当社のウェブサイト上の特定のUPDATEクエリは、非常に遅く実行され、必要以上に多くの行を調べることがあります。これはプライマリキーによってフィルタリングされるので、MySQLは常に1つの行だけを調べる必要があると思います。ここでプライマリキーによるMySQL UPDATEクエリが非常に遅い場合があります

は、MySQLのスロークエリログからのいくつかの例です:

# 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'; 

クエリはいえ、多くの場合よりも実行されるので、常にこの動作を公開しません。 また、同じクエリを手動で実行すると、正常に実行されてすぐに戻ります。

私も、私の知る限り、それは問題ないはずです見ることができるように、テーブルを検証し、:

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) 

もう一つは、MySQLサーバが時々ロックアップおよび接続の受け入れを停止していることである、とするたびに、これは通常、I起こります障害の直前に、これらの遅いクエリの1つをログファイルで見つけます。他のログファイルに関連するエラーメッセージは表示されませんが、MySQLを再起動すると再度応答します。

誰も何が起こっているのか、問題を絞り込むためにチェックできるものはありますか?

EDIT:専用サーバーでMySQL 5.0.51aを使用しています。現在、PHP 5.2.6を実行している6台のWebサーバーとPDO経由でMySQLサーバーに接続しています。すべてのサーバがDebian Lennyを実行しています。遅いクエリは、すべてのWebサーバーで発生します。

EDIT:ここで引用符なしで、関連するクエリのEXPLAINです:奇妙ですが、私の推測がある

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

これは本当に興味深いことですが、なぜこれもこれを行うのですか? EXPLAIN SELECT *を試しましたか? 'フォルダ'どこから 'id' =何か? –

答えて

1

愚かな私。 foldersテーブルにいくつかのトリガがあったことを忘れていました。もちろん、これらのトリガの1つのクエリが原因で問題が発生しました。...

フォルダ間の関連付けを維持する追加テーブルtreeがあります。トリガーは、フォルダーが削除または階層内で移動されたときにこれらの関連付けを更新します。 UPDATEトリガーでは、新しい参照を追加する前に、既存のすべての参照を削除する必要があります。

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

childrenが、私は以前、私が必要とするフォルダのIDを格納する一時テーブルで次のように関連するDELETEクエリが始まりました。 は現在、いくつかの理由でMySQLがこのクエリを最適化することはできませんが、私はRIGHT JOINを使用する場合代わりにそれは完全に正常に動作します:私はこのクエリを変更しましたので、MySQLのスロークエリログが穏やか空のまま

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

、我々 MySQLのロックアップを経験していません。

1

それあなたのidフィールドはintですが、あなたが渡しているので可能性があり文字列(引用符付き)。文字列を使用せずに役立つかどうか試してみてください。

何が起こっているのかを正確に把握するには、同じWHERE句を持つSELECTにクエリを変更し、EXPLAINで実行します。このように:

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

違いがあるかどうかを確認してください。

More info on EXPLAIN

+0

違いはありません。また、それが本当に原因だった場合、私はいつもこのクエリが遅いと期待しています。とにかく助けてくれてありがとう! – toupeira