簡體   English   中英

使用子查詢和連接查詢更新行 - 真的很慢

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM