2015-04-19 156 views
5

我有一個MySQL表,10萬行,捕捉一些服務器日誌創建爲沒有索引的選擇查詢:更新,加入非常緩慢相比

CREATE TABLE `logs` ( 
    `id` INT NOT NULL AUTO_INCREMENT, 
    `ip` VARCHAR(16) NULL, 
    `date` DATETIME NULL, 
    `session_time` SMALLINT UNSIGNED NULL, 
    PRIMARY KEY (`id`)); 

我試圖計算會話時間爲相同IP的連續行之間的時間差異。我能做到這一點有以下選擇查詢花費不到一秒鐘:

SELECT * FROM logs AS a 
LEFT JOIN (
    SELECT id, 
     from_unixtime(@diff) AS starttime, 
     date AS endtime, 
     IF(@diff = 0, 0, (unix_timestamp(date) - @diff)/60) AS session_time1, 
     @diff := unix_timestamp(date) 
    FROM logs, 
     (SELECT @diff := 0) AS x 
    ORDER BY ip, logs.date 
) AS b ON 
    a.id = b.id 

然而,當我嘗試使用以前的查詢在更新加入更新時間會話,以下更新查詢需要超過600秒:

UPDATE logs AS a 
LEFT JOIN (
    SELECT id, 
     from_unixtime(@diff) AS starttime, 
     date AS endtime, 
     IF(@diff = 0, 0, (unix_timestamp(date) - @diff)/60) AS session_time1, 
     @diff := unix_timestamp(date) 
    FROM logs, 
     (SELECT @diff := 0) AS x 
    ORDER BY ip, logs.date 
) AS b ON 
    a.id = b.id 
SET session_time = session_time1; 

我錯過了什麼?

謝謝!

UPDATE:這裏是selectEXPLAIN

+----+-------------+------------+--------+---------------+------+--------+ 
| id | select_type | table | type | possible_keys | key | rows | 
+----+-------------+------------+--------+---------------+------+--------+ 
| 1 | PRIMARY  | a   | ALL | NULL   | NULL | 109029 | 
| 1 | PRIMARY  | <derived2> | ALL | NULL   | NULL | 108680 | 
| 2 | DERIVED  | <derived3> | system | NULL   | NULL | 1  | 
| 2 | DERIVED  | logs  | ALL | NULL   | NULL | 109029 | 
| 3 | DERIVED  | NULL  | NULL | NULL   | NULL | NULL | 
+----+-------------+------------+--------+---------------+------+--------+ 
+1

'WHERE ip ='...''?看起來你正在更新所有100k條目,但是你正在選擇的條目('LEFT JOIN' =不符合第一組中的選擇規則的元素)。嘗試使用'INNER JOIN'? –

+0

謝謝亞歷杭德羅,但我不太理解你的評論。內連接爲什麼會更好? 「where」條款是什麼意思? – kahlo

+0

對不起,我應該更好地解釋它。當你使用'UPDATE'時,你通常使用'WHERE'子句來過濾哪些數據應該被更新。在你的情況下,如果你想更新一個特定的IP地址,那麼'WHERE IP ='''應該更好地處理那些具有特定IP的數據(我想你的查詢正在處理你表中的每條記錄,即使並非全部都在更新)。 –

回答

0

開始了與session_time是所有行NULL。更改查詢方式有兩種:

  • (末)
  • session_time添加WHERE session_time IS NULL到UPDATE到NULL,如果你沒有截止時間,否則正確設置。

第一天晚上,它會像現在一樣慢,但之後,它會快得多,因爲它只會在少數「新」行上工作。

編輯

JOIN需求(通常)的ON子句。如何連接logsalogsPRIMARY KEYEXPLAIN顯示它需要運行通過logsa的109K * 108K組合;它應該只有109K。

此外,刪除LEFT,除非有一些需要它。

+0

謝謝里克,我包括你的建議。然而,這個查詢已經包含了一天內生成的新信息(每天100k行)。我仍然對什麼可能導致這種時間差異並修復它感興趣。 – kahlo

+0

如果你正在運行5.6,請發佈'EXPLAIN SELECT ...'和'EXPLAIN UPDATE ...'。也許這將表明優化器正在做一些不同的事情。 –

+0

我剛添加了'EXPLAIN SELECT ...',但由於我運行的版本是5.5.29,所以我不能添加'EXPLAN UPDATE ...',並且以前的5.6.3是不允許的。 – kahlo