为什么这个更新查询没有完成?
Why does this update query not complete?
我有 2 个表,customers(3000 行)和 phone_call_log(350 000 行)。
我需要使用通话记录具体化每个客户的最后一次通话时间(前端搜索速度更快)
索引在:
- start_time(时间戳)
- 被调用者(bigint(32)未签名)
- 来电者(bigint(32)未签名)
- 电话号码(bigint(32) 无符号)
- last_call(时间戳)
运行 对于调用者/被调用者列,没有 OR 语句的查询在 < 2 秒内完成,但是在 OR 就位的情况下,它不会完成(我不允许它 运行 测试时间超过 30 分钟)。
UPDATE customers
SET customers.last_call = (
SELECT max(phone_call_log.start_time)
FROM phone_call_log
WHERE phone_call_log.callee = customers.phonenumber
OR phone_call_log.caller = customers.phonenumber
)
WHERE customers.phonenumber IS NOT NULL
AND length(customers.phonenumber) > 6
AND customers.phonenumber > 1000000;
使用 OR
的查询无法使用索引(效率不高)。我建议您尝试以下操作:
UPDATE customers
SET last_call = GREATEST(
(SELECT MAX(start_time) FROM phone_call_log WHERE callee = customers.phonenumber),
(SELECT MAX(start_time) FROM phone_call_log WHERE caller = customers.phonenumber)
)
请注意 GREATEST
存在 NULL 值问题。
最快
更改数据流以在有来电时更新customers.last_call
。
更新加入
UPDATE
使用 JOIN
比使用 IN ( SELECT ... )
效果更好
或
OR
是性能杀手。该查询可能会针对每个客户扫描整个 phone_call_log
。
一个解决方法是做两个 UPDATEs
并有合适的索引:
UPDATE
SET customers.last_call = GREATEST( customers.last_call,
( select max(phone_call_log.start_time)
FROM phone_call_log
WHERE phone_call_log.callee = customers.phonenumber
)
WHERE ...
UPDATE
SET customers.last_call = GREATEST( customers.last_call,
( ... caller ... )
)
WHERE ...
phone_call_log
:
上需要这些索引
INDEX(callee, start_time)
INDEX(caller, start_time)
和 删除调用者和被调用者当前的 1 列索引。
数据类型
将 BIGINT
用于 phone 数字可能是错误的并且适得其反,特别是考虑到 LENGTH(customers.phonenumber) > 6
.
事实上,所有这些都归结为一个测试:
where customers.phonenumber is not null
AND LENGTH(customers.phonenumber) > 6
AND customers.phonenumber > 1000000;
无论如何,每个 >
检查 NOT NULL
;根据数据类型,仅使用其中一个。并将其编入索引。
(请提供 SHOW CREATE TABLE
;'English' 不太准确。)
我有 2 个表,customers(3000 行)和 phone_call_log(350 000 行)。
我需要使用通话记录具体化每个客户的最后一次通话时间(前端搜索速度更快)
索引在:
- start_time(时间戳)
- 被调用者(bigint(32)未签名)
- 来电者(bigint(32)未签名)
- 电话号码(bigint(32) 无符号)
- last_call(时间戳)
运行 对于调用者/被调用者列,没有 OR 语句的查询在 < 2 秒内完成,但是在 OR 就位的情况下,它不会完成(我不允许它 运行 测试时间超过 30 分钟)。
UPDATE customers
SET customers.last_call = (
SELECT max(phone_call_log.start_time)
FROM phone_call_log
WHERE phone_call_log.callee = customers.phonenumber
OR phone_call_log.caller = customers.phonenumber
)
WHERE customers.phonenumber IS NOT NULL
AND length(customers.phonenumber) > 6
AND customers.phonenumber > 1000000;
使用 OR
的查询无法使用索引(效率不高)。我建议您尝试以下操作:
UPDATE customers
SET last_call = GREATEST(
(SELECT MAX(start_time) FROM phone_call_log WHERE callee = customers.phonenumber),
(SELECT MAX(start_time) FROM phone_call_log WHERE caller = customers.phonenumber)
)
请注意 GREATEST
存在 NULL 值问题。
最快
更改数据流以在有来电时更新customers.last_call
。
更新加入
UPDATE
使用 JOIN
比使用 IN ( SELECT ... )
或
OR
是性能杀手。该查询可能会针对每个客户扫描整个 phone_call_log
。
一个解决方法是做两个 UPDATEs
并有合适的索引:
UPDATE
SET customers.last_call = GREATEST( customers.last_call,
( select max(phone_call_log.start_time)
FROM phone_call_log
WHERE phone_call_log.callee = customers.phonenumber
)
WHERE ...
UPDATE
SET customers.last_call = GREATEST( customers.last_call,
( ... caller ... )
)
WHERE ...
phone_call_log
:
INDEX(callee, start_time)
INDEX(caller, start_time)
和 删除调用者和被调用者当前的 1 列索引。
数据类型
将 BIGINT
用于 phone 数字可能是错误的并且适得其反,特别是考虑到 LENGTH(customers.phonenumber) > 6
.
事实上,所有这些都归结为一个测试:
where customers.phonenumber is not null
AND LENGTH(customers.phonenumber) > 6
AND customers.phonenumber > 1000000;
无论如何,每个 >
检查 NOT NULL
;根据数据类型,仅使用其中一个。并将其编入索引。
(请提供 SHOW CREATE TABLE
;'English' 不太准确。)