4

データベースの100.000行を更新しようとすると、次のコードで更新できますが、常にエラーが発生します。

エラー:コマンドが同期していません。現在、このコマンドを実行することはできません

これは更新であるため、結果は必要なく、それらを削除したいだけです。$ count変数は、データベースが1つの大きな更新ではなく更新のチャンクを取得するために使用されます。(データベースのいくつかの制限のため、1つの大きな更新が機能していません)。

mysqli_free_resultなどのさまざまなことを試しました...何も機能しませんでした。

    global $mysqliObject;

    $count = 0;    
    $statement = "";

    foreach ($songsArray as $song) {

        $id = $song->getId();
        $treepath = $song->getTreepath();

        $statement = $statement."UPDATE songs SET treepath='".$treepath."' WHERE id=".$id."; ";
        $count++;

        if ($count > 10000){

            $result = mysqli_multi_query($mysqliObject, $statement);

            if(!$result) {
                 die('<br/><br/>Error1: ' . mysqli_error($mysqliObject));    
            }



            $count = 0;

            $statement = ""; 
        }


    }
4

5 に答える 5

4

準備されたクエリを使用すると、DaveRandomとStevenVIが示唆するように、mysqldプロセスのCPU負荷が軽減されます。ただし、この場合、準備されたクエリを使用すると、実行時間に大きな影響があるとは思えません。あなたが抱えている課題は、songsテーブル内の100K行を更新しようとしていることであり、これには、物理​​ディスクサブシステムでの多くの物理I/Oが含まれます。ランタイムを支配するのは、これらの物理的な遅延(たとえば、PIOあたり最大10ミリ秒)です。各行に含まれるもの、テーブルで使用しているインデックスの数(特にツリーパスを含むもの)などの要素はすべて、この組み合わせに溶け込みます。

次のような単純なステートメントを準備するための実際のCPUコスト

UPDATE songs SET treepath="some treepath" WHERE id=12345;

この全体的な物理I/O遅延で失われ、これの相対的なサイズは、データを保存している物理サブシステムの性質に大きく依存します。単一のSATAディスク。SSD; 大容量キャッシュとSSDをサポートする一部のNAS..。

songs特に、Webフロントエンドを介したインタラクティブなリクエストのリソースとして同時にテーブルを使用している場合は、ここで全体的な戦略を再考する必要があります。100K行の更新には時間がかかります。ストレージの順序で100Kから100Kを更新する場合は、MYD組織に合わせて調整され、書き込みがより適切になりますが、キャッシュが改善されるため、時間がかかります。100万行からランダムな順序で100K行を更新する場合は、PIOの数がはるかに多くなります。

これを行うと、D/Bの全体的なパフォーマンスが大幅に低下します。

  • DBの並列使用への影響を最小限に抑えたいですか、それともオフラインで他のサービスとの専用バッチ操作としてこれを実行しようとしていますか?

  • 合計経過時間を最小限に抑えること、または全体的な影響の制約を受けて合理的に短く保つこと、あるいは単に死ぬことなく完了することを目標としています。

私はあなたが2つの賢明なアプローチを持っていることを提案します:(i)他のサービスへのオフラインのD/Bで適切なバッチ活動としてこれを行います。この場合、おそらくテーブルのロックを解除し、更新をALTER TABLE ... DISABLE /ENABLEKEYSで囲みます。(ii)これを、はるかに小さい更新セットと各セット間の遅延を使用したトリクル更新として実行し、D/Bをディスクにフラッシュできるようにします。

いずれにせよ、バッチサイズを削除します。multi_queryは基本的に、アウトプロセスmysqldの呼び出しに関係するヘッド上でRPCを最適化します。10のバッチは、これを90%削減します。この後、収穫逓減が発生します。特に、更新は物理的なI/Oを多用すると言っています。

于 2012-07-19T12:20:13.890 に答える
1

プリペアドステートメントを使用してこのコードを試してください。

// Create a prepared statement
$query = "
  UPDATE `songs`
  SET `treepath` = ?
  WHERE `id` = ?
";
$stmt = $GLOBALS['mysqliObject']->prepare($query); // Global variables = bad

// Loop over the array
foreach ($songsArray as $key => $song) {

  // Get data about this song
  $id = $song->getId();
  $treepath = $song->getTreepath();

  // Bind data to the statement
  $stmt->bind_param('si', $treepath, $id);

  // Execute the statement
  $stmt->execute();

  // Check for errors
  if ($stmt->errno) {
    echo '<br/><br/>Error: Key ' . $key . ': ' . $stmt->error;
    break;
  } else if ($stmt->affected_rows < 1) {
    echo '<br/><br/>Warning: No rows affected by object at key ' . $key;
  }

  // Reset the statment
  $stmt->reset();

}

// We're done, close the statement
$stmt->close();
于 2012-07-19T09:41:06.487 に答える
1

私はこのようなことをします:

  $link = mysqli_connect('host');
  if ( $stmt = mysqli_prepare($link, "UPDATE songs SET treepath=? WHERE id=?") ) {

    foreach ($songsArray as $song) {

        $id = $song->getId();
        $treepath = $song->getTreepath();

        mysqli_stmt_bind_param($stmt, 's', $treepath); // Assuming it's a string...
        mysqli_stmt_bind_param($stmt, 'i', $id);
        mysqli_stmt_execute($stmt);
    }
    mysqli_stmt_close($stmt);
  }
  mysqli_close($link);

またはもちろん、通常のmysql_queryですが、トランザクションで囲まれています。

于 2012-07-19T09:41:16.110 に答える
1

私は別の方法を見つけました...

これは実稼働サーバーではないため、100k行を更新する最も速い方法は、すべての行を削除し、新しい計算値を使用して100kを最初から挿入することです。更新する代わりにすべてを削除してすべてを挿入するのは少し奇妙に思えますが、それは非常に高速です。

前:時間今:秒!

于 2012-07-19T14:48:08.087 に答える
0

複数の更新を実行する前に、テーブルをロックしてキーを無効にすることをお勧めします。これにより、データベースエンジンが停止することを回避できます(少なくとも300,000行の更新の場合)。

LOCK TABLES `TBL_RAW_DATA` WRITE;
/*!40000 ALTER TABLE `TBL_RAW_DATA` DISABLE KEYS */;

UPDATE TBL_RAW_DATA SET CREATION_DATE = ADDTIME(CREATION_DATE,'01:00:00') WHERE ID_DATA >= 1359711;

/*!40000 ALTER TABLE `TBL_RAW_DATA` ENABLE KEYS */;
UNLOCK TABLES;
于 2019-04-10T16:14:07.930 に答える