我有一個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:這裏是select
的EXPLAIN
:
+----+-------------+------------+--------+---------------+------+--------+
| 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 |
+----+-------------+------------+--------+---------------+------+--------+
'WHERE ip ='...''?看起來你正在更新所有100k條目,但是你正在選擇的條目('LEFT JOIN' =不符合第一組中的選擇規則的元素)。嘗試使用'INNER JOIN'? –
謝謝亞歷杭德羅,但我不太理解你的評論。內連接爲什麼會更好? 「where」條款是什麼意思? – kahlo
對不起,我應該更好地解釋它。當你使用'UPDATE'時,你通常使用'WHERE'子句來過濾哪些數據應該被更新。在你的情況下,如果你想更新一個特定的IP地址,那麼'WHERE IP ='''應該更好地處理那些具有特定IP的數據(我想你的查詢正在處理你表中的每條記錄,即使並非全部都在更新)。 –