2012-06-01 60 views
4

我有麻煩的MySQL查詢性能。MySQL特定的查詢性能調優

表(InnoDB的):

+--------------------+---------------------+------+-----+-------------------+-------+ 
| Field    | Type    | Null | Key | Default   | Extra | 
+--------------------+---------------------+------+-----+-------------------+-------+ 
| st_resource_id  | varchar(32)   | NO | MUL | NULL    |  | 
| st_sub_resource_id | varchar(32)   | YES |  | NULL    |  | 
| st_title   | varchar(500)  | YES |  | NULL    |  | 
| st_resource_type | varchar(100)  | NO | MUL | NULL    |  | 
| st_site_id   | tinyint(4)   | NO | MUL | NULL    |  | 
| st_time   | timestamp   | NO | MUL | CURRENT_TIMESTAMP |  | 
| st_user_id   | int(10) unsigned | YES |  | NULL    |  | 
| st_full_access  | tinyint(1) unsigned | YES |  | NULL    |  | 
+--------------------+---------------------+------+-----+-------------------+-------+ 

索引:

+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table   | Non_unique | Key_name   | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| nr_statistics |   1 | resource_id  |   1 | st_resource_id  | A   |  1546165 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | resource_id  |   2 | st_sub_resource_id | A   |  1546165 |  NULL | NULL | YES | BTREE  |   | 
| nr_statistics |   1 | st_time   |   1 | st_time   | A   |  1546165 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id  |   1 | st_site_id   | A   |   16 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_resource_type |   1 | st_resource_type | A   |   16 |  10 | NULL |  | BTREE  |   | 
+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+ 

查詢:

SELECT st_resource_id AS docId, count(*) AS cnt 
FROM nr_statistics 
WHERE 
    st_resource_type = 'document' 
    AND st_sub_resource_id = 'text' 
    AND st_time > DATE_SUB(NOW(), INTERVAL 7 DAY) 
    AND st_site_id = 1 
GROUP BY st_resource_id 
ORDER BY cnt DESC 
LIMIT 0, 5; 

查詢計劃:

+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+ 
| id | select_type | table   | type | possible_keys      | key   | key_len | ref | rows | Extra          | 
+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+ 
| 1 | SIMPLE  | nr_statistics | index | st_time,st_site_id,st_resource_type | resource_id | 197  | NULL | 1581044 | Using where; Using temporary; Using filesort | 
+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+ 

表具有〜1,666,383行。查詢運行速度非常慢。在MySQL進程列表中,我長時間(> 1分鐘)在「複製到tmp表階段」中看到此查詢。查詢會生成沉重的I/O負載。我無法理解如何解決問題並加快查詢的執行速度。

如果問題是索引錯誤的結果,那麼哪些索引是正確的?

UPD。我創造了新的綜合指數:

| nr_statistics |   1 | st_site_id_2  |   1 | st_site_id   | A   |   16 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   2 | st_resource_type | A   |   16 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   3 | st_sub_resource_id | A   |  752018 |  NULL | NULL | YES | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   4 | st_time   | A   |  1504037 |  NULL | NULL |  | BTREE  |   | 
| nr_statistics |   1 | st_site_id_2  |   5 | st_resource_id  | A   |  1504037 |  NULL | NULL |  | BTREE  |   | 

現在查詢計劃是:

+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+ 
| id | select_type | table   | type | possible_keys | key   | key_len | ref | rows | Extra              | 
+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+ 
| 1 | SIMPLE  | nr_statistics | range | st_site_id_2 | st_site_id_2 | 406  | NULL | 21168 | Using where; Using index; Using temporary; Using filesort | 
+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+ 

查詢現在運行速度非常快(如0.0X秒),但我一直在使用新的指數給力:

SELECT st_resource_id as docId, count(*) AS Cnt 
FROM nr_statistics 
USE INDEX (st_site_id_2) 
WHERE st_resource_type = 'document' 
AND st_sub_resource_id = 'text' 
AND st_time > DATE_SUB(NOW() , INTERVAL 7 DAY) 
AND st_site_id = 1 
GROUP BY st_resource_id 
ORDER BY cnt DESC 
LIMIT 0 , 5; 

雖然問題得到解決(不漂亮,但有效的方式),我仍然有一些開放性的問題(見註釋)。

回答

2

(st_site_id, st_resource_type, st_sub_resourse_id, st_time, st_resource_id)上創建一個複合索引。

但是,您仍然在計劃中有temporaryfilesort,因爲您在訂購COUNT(*)時不能索引。

如果您需要快速和經常運行此查詢,你就必須創造條件,存儲計數爲每個站點/資源/ subresourse /周組合,並在觸發更新聚合表。

+0

,你告訴我,我已經創建複合索引。但MySQL仍然沒有使用它。當我強制MySQL使用新的索引查詢計劃更改(請參閱我的問題更新)。但性能變得很棒!查詢在0.0xxx秒內執行。對於這個建議很有幫助。 爲什麼MySQL不使用新索引automaticaly? 爲什麼4個獨立索引不能被MySQL使用?它幾乎與一個複合材料相同嗎? –

+0

@ValeraLeontyev:一個複合索引與4個獨立索引不完全相同。 4個索引不會形成您所有記錄所在的單一範圍。它們可以用來提高查詢速度(使用'index_merge'),但只能在相等條件下使用,而且它似乎是對查詢最有選擇性的'st_time'謂詞。 – Quassnoi

1

您是否嘗試在st_resource_type, st_resource_id, st_time and st_site_id上創建複合索引?它看起來像你有幾個索引,但大多數是在一個列或2列。通過使用更多列的組合索引可以提高性能。

0

在做多的where子句中編寫他們應該與你寫你的查詢訂單的訂單查詢。

在您的特定情況下,這將是:

CREATE INDEX stats_index ON nr_statistics (st_resource_type, st_sub_resource_id, st_time, st_site_id); 

這應該給你一個很好的速度提升。