やみくもに更新するか、どこを更新するか?
-
02-07-2019 - |
質問
ゲーム内の都市に関する情報を保持するテーブルがあります。各ターンに 1 つの建物を建設でき、これは値「usedBuilding」で記録されます。
各ターンで usedBuilding を 0 に変更するスクリプトを実行します。問題は、次の 2 つの方法のどちらが速いかということです。また、どちらの方法を使用するかは実際に重要でしょうか?
UPDATE cities SET usedBuilding = 0;
UPDATE cities SET usedBuilding = 0 WHERE usedBuilding = 1;
解決
一般に、2 番目のケース (WHERE 句を使用) は、トリガーの評価、トランザクション ログ、インデックスの更新などが発生しないため、より高速になります。未使用の行に。
0/1 値の分布によっては、実際には比較を行うよりもすべての行を更新する方が高速になる可能性がありますが、これはかなり劣化したケースです。
クエリのコストの約 95% は I/O であるため、WHERE 句を使用しても違いはありません (列にインデックスが作成されておらず、テーブル スキャンを実行しているため)、または大きな違いがあります (列にインデックスが作成されている場合、またはパーティション化されたテーブルなど)。いずれにせよ、痛くないです。
あなたが話しているデータの量に対して、実行計画や速度の違いに気付かないのではないかと思います。そのため、よく言えば学術的で、悪く言えば時期尚早な最適化になります。したがって、アプリにとって論理的に意味のあるものを使用することをお勧めします。
他のヒント
usedBuilding にインデックスが付けられている場合は、usedBuilding が true である行のみにアクセス/更新するため、where 句を使用する方が速くなります。インデックスが作成されていない場合は、とにかくテーブル全体のスキャンを実行することになるため、大きな違いはありません(少しも?)。
両方の方法をループで数千回試し、時間を計測してください。それはおそらく以下に依存します:このテーブルに実際にあるレコードの数と、それらがすべてメモリに収まるか、ディスクにページングする必要があるか。更新を実行する前に値 1 になっている建物の数 (これはおそらく 1 だと思います)。
どちらの方法を使用するかは問題ではありませんが、最も短い方法で問題が発生する可能性はおそらく最小限になります。自分が書いていないコードにバグがあるはずがありません。
これらのターンはどのくらいの頻度で発生しますか?このテーブルには何行あると予想されますか?答えが「1 秒に 1 回未満」または「10000 回未満」の場合は、心配する必要はありません。
もちろん、これに何らかの学術的な興味がある場合は別ですが。
「UsedBuilding = 0;」を「更新都市セットセット」にするためのトランザクションの数が少ないようです。より具体的なクエリよりも実行します。これに反対する主な理由は、列に複数の州が含まれている場合です。単にブール値である場合は問題ありませんが、常にそうなるかどうかを考えるのに時間を費やした方がよいかもしれません。
インデックスを作成すると、WHERE 句を使用して実行計画がより効率的になる可能性もあります。
最終的な答えを得る最善の方法は、さまざまなシナリオで大量のサンプル データを使用してプロファイリングを行うことです。
usedBuilding = 1 の値がおそらく 2% 程度でなければ、インデックス付けはまったく役に立ちません。
ただし、これら 2 つのステートメントは論理的に異なり、まったく異なることを意味する可能性があります。ただし、あなたの場合、それらが同じである場合は、where 句のないものを使用してください。
正確に何行あるでしょうか?小規模なオンライン ゲームの場合は、あまり気にしないのではないかと思います。
「cities」テーブルに対して複数の更新を実行している場合は、可能であればそれらをすべて 1 つの UPDATE ステートメントで実行することをお勧めします。
行に何らかの変更を加えるには、行全体を書き込むのと同じくらい多くの I/O が必要になるため (もちろん、インデックス付き列の更新にはインデックスの書き込みも必要です)、多数の行にヒットする複数の UPDATE を実行すると損失が発生します。
しかし、たとえば 1000 行未満であれば、まったく気にしません:)