2012-01-08 9 views
0

MySQLデータベースのすべての重複エントリを削除して、$ keepが何であるかに応じて最も早くまたは最新のエントリを残したいとします。私は以下を使用していますが、非常に遅いです:MySQLの重複レコードを効率よくプルーニングする(PHP)

function pruneDuplicates($keep) { 

    if($keep == 1) 
    $order = "ASC"; 
    else if ($keep == 0) 
    $order = "DESC"; 

    //Go through and find the duplicate hashes. Grab the IDs that correspond to them then delete all but one ID 

    $query = "SELECT HEX(hash) FROM hashes GROUP BY hash HAVING count(hash) > 1"; 

    $result = mysql_query($query) or die("ERROR: ".mysql_error()); 
    while ($row = mysql_fetch_array($result)) { 
     $query = "SELECT id from hashes WHERE hash = UNHEX('$row[0]') ORDER BY id $order LIMIT 1"; 
     $innerResult = mysql_query($query) or die("ERROR: ".mysql_error()); 
     $innerRow = mysql_fetch_array($innerResult); 
     $query = "DELETE FROM hashes WHERE hash = UNHEX('$row[0]') AND id != $innerRow[0]"; 
     echo $query."<br>"; 
     mysql_query($query) or die("ERROR: ".mysql_error()); 

    } 

    echo "Prune successful..."; 

} 

echo $クエリはデバッグ用です。このスクリプトは実行に数分かかりました。約80,000件のレコードを整理しました(私は100,000件以上のレコードを持っていますが、1,000,000以上のレコードがあると予想しています)。私はmysqladmin proc statを見ていて、削除に時間がかかることがわかりました。

+-----------+------------+------+-----+-------------------+----------------+ 
| Field  | Type  | Null | Key | Default   | Extra   | 
+-----------+------------+------+-----+-------------------+----------------+ 
| id  | int(11) | NO | PRI | NULL    | auto_increment | 
| date  | timestamp | NO |  | CURRENT_TIMESTAMP |    | 
| hash  | binary(16) | NO | MUL | NULL    |    | 

ハッシュがINDEXで次のように

私のテーブルの記述があります。

+0

「ハッシュ= 'hashtodelete' AND id!= 'onetokeep'」で「DELETEすべて」という単一の 'DELETE'クエリを使用することができると思われます。注:これは疑似コードです。そうするためのループは遅いでしょう。 –

+0

これは本質的に私がやっていることですが、それ以上の選択文を削除するにはハッシュを見つけなければなりません。重複するハッシュを見つける...各ハッシュの最初または最後のIDを取得する - > IDを削除するid!= idおよびhash = hashtodelete ... repeat – user974896

+0

ああ、わかります。さて、最初の 'hash'と' id'の値を取得すれば、2番目の 'SELECT'を取り除くことができると思います。あなたは['IN()'](http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in)のための文字列を構築してから、 'id'を[あなたが何をしていないかの 'id'sで' NOT(IN ...) '](http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_not-in)削除しません。 –

答えて

0

そのような行を頻繁に削除すると、速度を上げるために微調整しても遅くなります。一度にすべての行を削除するのではなく、クエリにLIMIT句を含めることで、一括して実行してみてください。さらに、あなたのウェブサイト上のリンクからではなく、cronジョブからスクリプトを実行してください。本当に安全であるようにするには、PHP実行時間制限を増減するか、削除フェーズ中にヒットしないようにしてください。

関連する問題