2017-08-29 68 views
0

我的問題解釋如下。SQL查詢執行時間急劇增加

這是我的服務器上運行我的PHP代碼現在:

$limit = 10000; 
$annee = '2017'; 

//Counting the lines I need to delete 
$sql = " SELECT COUNT(*) FROM historisation.cdr_".$annee." a 
     INNER JOIN transatel.cdr_transatel_v2 b ON a.id_cdr = b.id_cdr "; 
$t = $db_transatel->selectAll($sql); 

//The number of lines I have to delete 
$i = $t[0][0]; 

do { 

    if ($i < $limit) { 
     $limit = $i; 
    } 
    //The problem is comming from that delete 
    $selectFromHistoryAndDelete = " DELETE FROM transatel.cdr_transatel_v2 
            WHERE id_cdr IN (
             SELECT a.id_cdr FROM historisation.cdr_".$annee." a 
             INNER JOIN (SELECT id_cdr FROM historisation.cdr_transatel_v2) b ON a.id_cdr = b.id_cdr 
            ) 
            LIMIT " . $limit; 
    $delete = $db_transatel->exec($selectFromHistoryAndDelete, $params); 

    $i = $i - $limit; 

} while ($i > 0); 

The execution of the query.

正如你可以在圖片中看到,在第195循環的執行時間爲13和17秒之間。 它在第195次循環中增加到73秒,在第196次循環中增加到1305秒。

現在查詢運行2000秒。

查詢正在刪除沒有人正在使用的測試表中的行。

我正在刪除10000行10000以使查詢快速且不超載服務器。

我想知道爲什麼執行時間會像這樣增加,儘管最終會更快,因爲我通過內部連接會更快,因爲它們在表中的行數較少。

有沒有人有想法?

編輯:表引擎是MyISAM。

+0

回滾段。我認爲DB保持在某個地方刪除行來處理可能的回滾。嘗試在每次刪除後提交。 – StanislavL

+0

不幸的是,我已經盡力了,但是我的表在MyIASM中,並且它不支持回滾和提交。 – McKenneii

+1

桌子很大時,IN太慢。使用JOIN查找要刪除的行要快得多。 – vladatr

回答

0

根據您的最新評論,內部聯接是多餘的,因爲您要從包含要加入的值的表中刪除。實質上,您必須處理b.id_cdr = a.id_cdr兩次,因爲cdr_2017上比較的值數量不會被內部聯接更改,只是查詢要刪除的值的數量。

至於增量緩慢的原因,這是因爲您手動執行與SELECT cdr_id FROM cdr_2017 LIMIT 10000 OFFSET x相同的功能。

也就是說,您的查詢必須對cdr_2017執行全表掃描以確定要刪除的id值。在您刪除這些值時,SQL優化器必須通過cdr_2017表進一步移動以檢索值。

DELETE FROM IN(1,2,3,...10000) 
DELETE FROM IN(1,2,3,...20000) 
... 
DELETE FROM IN(1,2,3,...1000000) 

假設cdr_id得到的是增量的主鍵,來解決你可以使用從cdr_2017檢索到的最後一個索引來篩選選定的值的問題。 這會更快,因爲您現在正在利用查詢兩側的索引值,因此不再需要全表掃描來驗證連接的記錄。

$sql = " SELECT COUNT(a.cdr_id) FROM historisation.cdr_".$annee." a 
     INNER JOIN transatel.cdr_transatel_v2 b ON a.id_cdr = b.id_cdr "; 
$t = $db_transatel->selectAll($sql); 

//The number of lines I have to delete 
$i = $t[0][0]; 

//set starting index 
$previous = 0; 

do { 

    if ($i < $limit) { 
     $limit = $i; 
    } 

    $selectFromHistoryAndDelete = 'DELETE d 
FROM transatel.cdr_transatel_v2 AS d 
JOIN (
    SELECT @previous := cdr_id AS cdr_id 
    FROM historisation.cdr_2017 
    WHERE cdr_id > ' . $previous . ' 
    ORDER BY cdr_id 
    LIMIT 10000 
) AS a 
ON a.cdr_id = d.cdr_id'; 

    $db_transatel->exec($selectFromHistoryAndDelete, $params); 

    //retrieve last id selected in cdr_2017 to use in next iteration 
    $v = $db_transatel->selectAll('SELECT @previous'); //prefer fetchColumn 
    $previous = $v[0][0]; 

    $i = $i - $limit; 

} while ($i > 0); 

//optionally reclaim table-space 
$db_transatel->exec('OPTIMIZE TABLE transatel.cdr_transatel_v2', $params); 

你也可以重構使用cdr_id > $previous AND cdr_id < $last的限制條款,這也應該改進性能,刪除訂單。

雖然我想說明的是,在MyISAM數據庫引擎的操作過程中會執行cdr_transatel_v2上的表鎖。由於MySQL處理併發會話和查詢的方式,以這種方式進行批量刪除沒有太多收益,並且僅適用於InnoDB和事務。尤其是當使用PHP和FastCGI時,與Apache mod_php相反。由於不在cdr_transatel_v2上的其他查詢仍將被執行,並且cdr_transatel_v2上的寫入操作仍將排隊。如果使用mod_php,我會將限制減少到1,000記錄以減少隊列時間。 欲瞭解更多信息,請參閱https://dev.mysql.com/doc/refman/5.7/en/internal-locking.html#internal-table-level-locking


替代做法。

考慮到需要刪除的大量記錄,當刪除的記錄超過保留的記錄時,通過使用INSERT而不是DELETE來反轉操作會更有益。

#ensure the storage table doesn't exist already 
DROP TABLE IF EXISTS cdr_transatel_temp; 

#duplicate the structure of the original table 
CREATE TABLE transatel.cdr_transatel_temp 
LIKE transatel.cdr_transatel_v2; 

#copy the records that are not to be deleted from the original table 
INSERT transatel.cdr_transatel_temp 
SELECT * 
FROM transatel.cdr_transatel_v2 AS d 
LEFT JOIN historisation.cdr_2017 AS b 
ON b.cdr_id = d.cdr_id 
WHERE b.cdr_id IS NULL; 

#replace the original table with the storage table 
RENAME TABLE transatel.cdr_transatel_v2 to transatel.backup, 
    transatel.cdr_transatel_temp to cdr_transatel_v2; 

#remove the original table 
DROP TABLE transatel.backup; 
+0

感謝您花時間思考並回答。如果我能找到第一個解決方案,我會明確地嘗試第一個解決方案。 @Vladatr談到了IN表演,所以我沒有它就做了我的查詢。現在刪除運行在〜0.07秒。我會嘗試查看您的查詢是否更快。再次感謝您的幫助 ! – McKenneii