[英]Update rows using sub query & join query - really dead slow
我需要將表'A'
標志從'X'
重置為'Y'
,其中行的update_date滿足條件1. update_date > 1 month, 2. flag = 'X' & 3. type = 1
。
並且針對另一個表'B'
檢查update_date。 我希望以下查詢將解釋我究竟需要什么。 此查詢也適合我。 但問題是需要花費太長時間。 實際上我的表A & B
更大,幾乎包含十億行,大約有10列。
當我運行我的子查詢選擇A.id
我立即得到了結果。
SELECT a.id
FROM A a
JOIN B b
ON (a.id = b.id
AND a.name = b.name
AND a.type = 1
AND a.flag = 'X'
AND a.update_date > DATE_SUB(NOW(), INTERVAL 1 MONTH) tmp_table)
但是只有更新查詢即使我放了限制也需要花費很多時間。
UPDATE A
SET flag='Y'
WHERE id IN (SELECT a.id
FROM A a
JOIN B b
ON (a.id = b.id
AND a.name = b.name
AND a.type = 1
AND a.flag = 'X'
AND a.update_date > DATE_SUB(NOW(), INTERVAL 1 MONTH) tmp_table))
LIMIT 100
我正在尋找我的查詢的替代解決方案,使其快速。 希望我能為它編寫一個存儲過程。 但是在SP
我應該為每個target_ids循環一次嗎?
我不希望在PHP中編寫兩個單獨的查詢,因為我的PHP腳本中有很多線程在cron上運行,返回相同的結果(時間延遲)。
還要注意,我確實有足夠的列索引。
希望通過限制更新限制。 即,為每次運行更新1000+條記錄。
改變與存在
EXISTS會更快,因為一旦發動機發現了撞擊,它就會退出,因為條件證明是正確的。 使用IN,它將在進一步處理之前收集子查詢中的所有結果。
UPDATE A a
JOIN B b
ON (a.id = b.id
AND a.name = b.name
AND a.type = 1
AND a.flag = 'X'
AND a.update_date > DATE_SUB(NOW(), INTERVAL 1 MONTH))
SET a.flag='Y'
ORDER BY a.id LIMIT 1000;
EDITED支持LIMIT的替代品(IT將僅更新前100條記錄)
SET @rn = 0;
UPDATE A a
JOIN (SELECT @rn:=@rn+1 AS rId, id, name FROM B b
JOIN A a
ON (@rn < 100 AND a.id = b.id
AND a.name = b.name
AND a.type = 1
AND a.flag = 'X'
AND a.update_date > DATE_SUB(NOW(), INTERVAL 1 MONTH)
)
) b
ON (a.id=b.id)
SET a.flag='Y'
WHERE b.rId < 100;
使用exists子句
Update A a
SET a.flag='Y'
WHERE EXISTS (SELECT 1 FROM B b WHERE a.id = b.id
AND a.name = b.name
AND a.type = 1
AND a.flag = 'X'
AND a.update_date > DATE_SUB(NOW(), INTERVAL 1 MONTH))
ORDER BY a.id LIMIT 1000;
希望這可以幫助
您也可以使用聯接
UPDATE A
LEFT JOIN (SELECT
a.id
FROM A AS a
JOIN B AS b
ON a.id = b.id
WHERE a.name = b.name
AND a.type = 1
AND a.flag = 'X'
AND a.update_date > DATE_SUB(NOW(), INTERVAL 1 MONTH)) AS l
ON l.id = A.id
SET flag = 'Y'
WHERE id = l.id
最后,我得到了性能更好的優化查詢。 簡單地加入臨時表。
UPDATE A AS a JOIN (
SELECT a.id FROM A AS a JOIN B AS b ON
b.type = a.type
AND b.name = a.name
AND b.last_update_date < DATE_SUB(NOW(), INTERVAL 1 MONTH)
AND a.type = 1
AND a.flag = 'X'
ORDER BY a.id DESC LIMIT 1000)
AS source ON source.id = a.id
SET flag = 'Y';
感謝http://www.xaprb.com/blog/2006/08/10/how-to-use-order-by-and-limit-on-multi-table-updates-in-mysql
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.