2011-03-02 277 views
0

請你幫我優化這個查詢。我花了很多時間,並且仍然無法將其改寫成足夠快的速度(比如說運行在秒鐘之內,而不是現在的分鐘)。MySQL查詢優化

查詢:

SELECT m.my_id, m.my_value, m.my_timestamp 
    FROM (
    SELECT my_id, MAX(my_timestamp) AS most_recent_timestamp 
     FROM my_table 
     WHERE my_timestamp < '2011-03-01 08:00:00' 
     GROUP BY my_id 
) as tmp 
LEFT OUTER JOIN my_table m 
ON tmp.my_id = m.my_id AND tmp.most_recent_timestamp = m.my_timestamp 
ORDER BY m.my_timestamp; 

MY_TABLE定義如下:

CREATE TABLE my_table (
    my_id INTEGER NOT NULL, 
    my_value VARCHAR(4000), 
    my_timestamp TIMESTAMP default CURRENT_TIMESTAMP NOT NULL, 
    INDEX MY_ID_IDX (my_id), 
    INDEX MY_TIMESTAMP_IDX (my_timestamp), 
    INDEX MY_ID_MY_TIMESTAMP_IDX (my_id, my_timestamp) 
); 

該查詢的目標是選擇最近的my_value每個my_id一些時間戳之前。 my_table包含約1億個條目,並且需要大約8分鐘才能完成。

解釋:

 
+----+-------------+-------------+-------+------------------------------------------------+-------------------------+---------+---------------------------+-------+---------------------------------------+ 
| id | select_type | table  | type | possible_keys         | key      | key_len | ref      | rows | Extra         | 
+----+-------------+-------------+-------+------------------------------------------------+-------------------------+---------+---------------------------+-------+---------------------------------------+ 
| 1 | PRIMARY  | <derived2> | ALL | NULL           | NULL     | NULL | NULL      | 90721 | Using temporary; Using filesort  | 
| 1 | PRIMARY  | m   | ref | MY_ID_IDX,MY_TIMESTAMP_IDX,MY_ID_TIMESTAMP_IDX | MY_TIMESTAMP_IDX  | 4  | tmp.most_recent_timestamp | 1 | Using where       | 
| 2 | DERIVED  | my_table | range | MY_TIMESTAMP_IDX        | MY_ID_MY_TIMESTAMP_IDX | 8  | NULL      | 61337 | Using where; Using index for group-by | 
+----+-------------+-------------+-------+------------------------------------------------+-----------------------+---------+---------------------------+------+---------------------------------------+ 
+2

您確定這是您發佈的查詢的查詢計劃嗎?該計劃提到表「nv」,但查詢中沒有這樣的表。該查詢可能不是正確的,因爲子選擇中的my_id的值可能不是(實際上不可能是)my_timestamp = MAX(my_timestamp)所在行的id。 – outis 2011-03-02 14:26:49

+0

哪個版本的mysql?以及爲什麼表名1被刪除。 – Zimbabao 2011-03-02 14:27:58

+0

不應該將您的連接條件設爲'... AND tmp.most_recent_timestamp = m.my_timestamp ...'?內部查詢也看起來缺少一個「GROUP BY」。 – 2011-03-02 14:32:28

回答

0

我注意到在解釋計劃中,優化器使用MY_ID_MY_TIMESTAMP_IDX索引爲子查詢,但不是外部查詢。

您可以使用索引提示進行加速。我還更新了ON子句以使用其別名引用tmp.most_recent_timestamp。

SELECT m.my_id, m.my_value, m.my_timestamp 
    FROM (
    SELECT my_id, MAX(my_timestamp) AS most_recent_timestamp 
     FROM my_table 
     WHERE my_timestamp < '2011-03-01 08:00:00' 
     GROUP BY my_id 
) as tmp 
LEFT OUTER JOIN my_table m use index (MY_ID_MY_TIMESTAMP_IDX) 
ON tmp.my_id = m.my_id AND tmp.most_recent_timestamp = m.my_timestamp 
ORDER BY m.my_timestamp; 
+0

@IKE,我糾正了這個查詢。在準備SCCE時錯過了「group by」聲明。問題是我必須爲每個'my_id'獲取「最新的時間戳」。 – 2011-03-02 14:55:12

+0

Gotcha。我會更新我的答案以反映這一點。 – 2011-03-02 16:08:41

+0

@Ike,不幸的是我自己嘗試過,但這並沒有改變優化器的行爲。據我瞭解這是一個MySQL功能(http://www.mysqlperformanceblog.com/2006/08/31/derived-tables-and-views-performance/)。在這一點上,我認爲仍然可以在不創建臨時表或視圖的情況下調整查詢。 – 2011-03-03 14:57:11

1

一招得到一個最新記錄可以一起與「限1」連同"self" join

財產以後這樣的(未測試)使用order by,而不是max aggregation

SELECT m.my_id, m.my_value, m.my_timestamp 
FROM my_table m 
WHERE my_timestamp < '2011-03-01 08:00:00' 
ORDER BY m.my_timestamp DESC 
LIMIT 1 
; 

更新以上不會因爲分組工作是必需的...
其他解決方案具有WHERE-IN-SubSelect而不是您使用的JOIN。
可能會更快。請用您的數據進行測試。

SELECT m.my_id, m.my_value, m.my_timestamp 
FROM my_table m 
WHERE (m.my_id, m.my_timestamp) IN (
    SELECT i.my_id, MAX(i.my_timestamp) 
    FROM my_table i 
    WHERE i.my_timestamp < '2011-03-01 08:00:00' 
    GROUP BY i.my_id 
) 
ORDER BY m.my_timestamp; 
+0

我們需要所有最近的對(id,value)不僅是最近的一對。 – 2011-03-02 14:53:23

+0

拉斯維加斯不是優化,但實際上降低了性能。根據:http://www.mysqlperformanceblog.com/2010/10/25/mysql-limitations-part-3-subqueries/ – 2011-03-05 16:51:18

2

如果我理解正確的話,你應該能夠刪除嵌套的選擇完全由my_timestamp下降where子句移動到主查詢,訂單和限制1.

SELECT my_id, my_value, max(my_timestamp) 
FROM my_table 
WHERE my_timestamp < '2011-03-01 08:00:00' 
GROUP BY my_id 

*編輯 - 增加了最大和組

+0

將ORDER BY更改爲DESC,這是完美的。 – 2011-03-02 14:38:22

+0

唯一的問題是我們需要所有'my_id'的最新條目。我認爲這個查詢只產生一個結果。 – 2011-03-02 14:51:04

+0

@Alex:你想要多少結果? – 2011-03-02 14:57:49