2017-09-26 40 views
0

我可以更新我用於連接的同一列嗎?看起來我可以,但我的腳本崩潰了。MySQL設置JOIN ON域是否有效? 「加入a = b SET a = c」

背景:我有一箇舊數據庫,我正在遷移。我正在通過在PHP循環中運行的大量MySQL查詢處理它。循環工作人員很好,每個查詢需要0.5到1 MB的內存來處理。直到它擊中這個查詢,突然需要什麼記憶我已經分配給PHP的101%:

UPDATE a.t1 
    INNER JOIN t2 
    ON t1.category = t2.oldcategory 
SET t1.category = t2.newcategory 
WHERE t1.category <> ''; 

當memory_limit的設置爲128M拋出的錯誤是:

PHP Fatal error: Allowed memory size of 134217728 bytes exhausted 
(tried to allocate 12288 bytes) 

當我碰到memory_limit的到256M的錯誤是:

PHP Fatal error: Allowed memory size of 268435456 bytes exhausted 
(tried to allocate 32768 bytes) 

但是這非常類似於查詢運行得很好:

UPDATE a.t1 
    INNER JOIN t2 
    ON t1.category = t2.oldcategory 
SET t1.series = t2.series_term 
WHERE t1.category <> '' AND t2.newcategory <> ''; 

PHP代碼的請求:

$queries = array (
// dozens of MySQL queries here, like this: 
["Count users", 
"SELECT id from $s2.$usr;" 
], 
) 

foreach ($queries as $query){ 
    $mtime = time(); 
    $result = mysqli_query($link, $query[1]); 
    $mem = number_format((memory_get_usage()/1024/10124),2); 
    $mtime = time() - $mtime; 
    $mtime = gmdate("i:s", $mtime); 

    if ($result) { 
    $rows = number_format(mysqli_affected_rows($link)); 
    echo "<tr><td>$mtime</td><td>$rows</td><td>$query[0] — $mem Mb</td></tr>"; 
    } else { 
    $rows = mysqli_error($link); 
    echo "<tr><td>X</td><td>X</td><td>".$query[0]."<br><span style='color:red;'>".$rows."</span></td></tr>"; 
    } 
} 

有什麼關於用於ON同一列使用SET非法或遞歸?

UPDATE:

我只是創建了兩個小的測試表,併成功運行此查詢:

# works 
UPDATE table1 t1 
    JOIN table2 t2 
    ON t1.column1 = t2.column1 
SET t1.column1 = t2.column2 
WHERE t1.column1 <> ''; 

更新2:

我編輯的WHERE子句,現在它在正常運行。使用0.04 Mb內存19秒:

UPDATE a.t1 
    INNER JOIN t2 
    ON t1.category = t2.oldcategory 
SET t1.category = t2.newcategory 
WHERE t1.category <> '' AND t1.category <> t2.newcategory; 
+0

請出示PHP代碼,以及,你可能會看到'memory_limit'在'php.ini' –

+0

設置做了,而不是使用整個數據庫進行更新,不能將其設置爲塊,例如,對於每50,000次更新,而不是一次更新查詢。 – rahul

+0

Akshay Hegde,我的PHP限制設置爲256M,從第一個錯誤後從128M提高。 – Slam

回答

0
我覺得下面的代碼也會運行的很好! **這裏代碼:** UPDATE a.t1 INNER JOIN T2 ON t1.category = t2.oldcategory #SET t1.series = t2.series_term ##與出SET WHERE t1.category '' AND t2.newcategory''; **和t2.newcategory''**讓它工作的條件越多。 我認爲這是更多的條件讓它工作,因爲更多的條件過濾更多的數據,並讓MySQL使用較少的內存。

對不起,剛剛看了你的代碼,你可以不設置連接條件的數據,你會在無限循環

+0

但是你的代碼中沒有設置任何東西。我需要用新值更新t1.category。 – Slam

+0

你明白我的答案嗎?如果你想更新t1.category,你應該添加更多的條件或增加memory_limit – Carson

+0

我寫道,我已經增加了限制。無論我設置了多大的限制,該查詢都使用全部內存的101%。它使用了257M,當它使用了僅僅0.5M的非常相似的查詢時。而t2.newcategory沒有空行。 – Slam

0

沒有你t update same columns which are used in join statement. Think about the logic. It updates one row and it has to recheck the value again since it S使用相同的列加入。所以這成爲無窮的遞歸,這將導致你的內存不足的例外。

爲什麼不先保存需要更新的id和鍵值數組中的值。 然後運行一個循環並分別更新?

SELECT t1.id,t2.newcategory from t1 
    INNER JOIN t2 
    ON t1.category = t2.oldcategory 

運行foreach循環的結果列表,並更新各行

foreach($queryResul as $row){ 
UPDATE t1 SET t1.category = $row->newcategory where t1.id = $row->id; } 
+0

爲什麼需要重新檢查該值?我假定操作順序首先執行JOIN ... ON,製作一個大表,然後爬行執行SET的行。那是不正確的? – Slam

+0

我不知道鍵值數組是什麼。你能提出代碼嗎? – Slam

+0

「重新檢查」或重新運行循環是爲了防止無限遞歸 檢查更新的答案 – BRjava

相關問題