2009-07-02 72 views
3

我們網站上的特定UPDATE查詢有時運行非常緩慢,並且檢查的行數多於必要數量。它通過主鍵過濾,所以我希望MySQL總是隻需要檢查一行。通過主鍵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服務器有時會鎖定並停止接受連接,每一次遇到這種情況,我通常在失敗之前立即在日誌文件中找到這些慢查詢之一。我在其他日誌文件中看不到任何相關的錯誤消息,但是MySQL重新啓動會使其再次響應。

有沒有人知道發生了什麼事情,或者我可以檢查什麼來縮小問題的範圍?

編輯:我們在專用服務器上使用MySQL 5.0.51a,目前有6個webservers運行PHP 5.2.6並通過PDO連接到MySQL服務器。所有的服務器都在運行Debian Lenny。緩慢的查詢發生在所有的Web服務器上。

編輯:下面是相關的查詢的解釋,不管有沒有行情:

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 * FROM`folders` WHERE`id` = something? – 2009-07-02 14:46:05

回答

1

傻了。我忘記folders表中有一些觸發器,當然這是一個內部查詢導致我的問題...

有一個額外的表tree維護文件夾之間的關聯,當在層次結構中刪除或移動文件夾時觸發器更新這些關聯。在UPDATE觸發器中,它必須在添加新引用之前刪除對該文件夾的所有現有引用。相關DELETE查詢開始如下:

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

children是我事先存儲的文件夾ID的我需要一個臨時表。 現在,由於某種原因,MySQL不能優化這個查詢,但如果我使用一個RIGHT JOIN而是工作完全正常:

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

既然我已經改變了這個查詢MySQL的慢查詢日誌仍然幸福地空着,我們沒有經歷任何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 2009-07-02 15:06:46