我有一个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的数据(我想你的查询正在处理你表中的每条记录,即使并非全部都在更新)。 –