0

大量のデータを含むmysqlテーブルがあります。このテーブルのすべての行には、純粋なSQLでは簡単に表現できない方法で1つのフィールドを変更する必要があります。

テーブルを1行ずつループして、すべてのエントリを1つずつ更新できるようにしたいと思います。ただし、これを行うには、次のようなことを行います。

$sql = "SELECT id,value FROM objects";
foreach ($dbh->query($sql) as $row)
{
    $value = update_value( $row['value'] );
    $id = $row['id'];
    $update_sql = "UPDATE objects SET value='$value' WHERE id=$d";
    $dbh->query( $update_sql );
}

これは何か悪いことをしますか?(潜在的に遅いこと以外は?)

明確化:特に、foreach内の1回のヒットですべてのデータを取得するのではなく、カーソルを使用して最初に選択することを心配しています。その後、ループ内の更新によって引き起こされるカーソルの無効化について不明な点があります。「別のカーソルでスキャンしているときに同じテーブルを更新しない」などのルールがある場合、それは巨大なテーブルにのみ表示される可能性が高いため、小さなテストケースを実行してもほとんど役に立ちません。

この方法で作業する際の特定の問題ではなく、これを実行しても問題ないと言うドキュメントを誰かが私に指摘できれば、それも素晴らしいことです。

4

2 に答える 2

0

単一のクエリの結果は一貫しているため、更新による影響はありません。心に留めておくべき:

  1. プリペアドステートメントを使用します。毎回クエリ全体ではなく値のみが転送されるため、プロセスとデータベース間のトラフィックが減少します。

  2. 同時に実行されている他のプロセスが心配な場合は、トランザクションと適切なロックを使用する必要があります。

    // transaction started
    SELECT id,value 
    FROM objects 
    LOCK IN SHARE MODE
    
    // your other code
    
    // commit transaction
    
于 2013-03-21T13:02:07.970 に答える
0

ゲートのすぐ外に2つのオプションがあるようです。

  1. (ストレートフォワード):'fetchAll'のようなものを使用して、ループを開始する前に最初のクエリのすべての結果を取得します。これにより、カーソルが重ならないようにすることができます。
  2. (もっとわかりにくい):これを変更して、('update_value'の代わりに)ストアド関数を使用して、2つのクエリを単一の' update objects set value = some_function(id)'に変換できるようにします。

このサイズと期間によっては、事前にすべてをロックする必要がある場合があります。

于 2013-03-21T12:54:14.457 に答える