4

1対多の関係にある2つのテーブルがあります。テーブルの各行について、の行を参照する0個以上の行がテーブルfooに存在する可能性があるとします。barfoo

クライアントは、のすべての行について、の行をbar参照する行の数を知りたいと考えています。foofoo

私は次のクエリでこれを達成することができます:

SELECT count(bar_id) FROM bar WHERE bar.foo_id = foo.foo_id;

しかし、テーブルfoobarが大きかった場合はどうなりますか?Sayfooには100万行あり、bar1000万行あります。fooまた、の行の99%が、それを参照する行の数が1,000行未満であるとしましょうbar。クライアントが通常、一度に約100行を要求するとしますfoo

外部キーのインデックスを使用してnaivecount()クエリを使用する必要がありますか、それともカウンターを保持する方がよいでしょうか?カウンターを維持することさえ可能ですか?のトリガーを使用してアトミックインクリメントとデクリメントでカウンターを更新することでbar、それは可能だと思いますが、間違っている可能性があります。

4

2 に答える 2

5

countおそらく直観に反するかもしれませんが、ワークロードが読み取りに偏っていない限り、単純なアプローチの方が高速であることがわかるでしょう。

この理由は、カウンター テーブルの効果は更新をシリアル化することであり、そのため、特定の更新を行っているトランザクションは常に 1 つだけ実行fooできるからです。これは、カウンターを更新するトリガーの更新によりfoo、カウンター テーブル内のそのエントリがロックされ、トランザクションがロールバックまたはコミットされるまで解放されないためです。

さらに悪いことに、トランザクションが複数に影響を与え、foo別のトランザクションにも影響を与える場合、デッドロックのためにトランザクションの 1 つが中止される可能性が高くなります。

変更する正当な理由があるまでは、単純なカウントに固執してください。

于 2013-02-21T08:38:54.563 に答える
4

インデックスの優れた点は、クエリ操作に対して対数の複雑さを提供することです。したがって、10*10^6行の場合、インデックスln(10*10^6)=16.1は 1 つの特定の ID を見つけるために比較を行うだけで済みます。1 億行にすれば、さらに 2 ~ 3 回の比較を行うだけで済みます。要するに、インデックスはテーブルのサイズをあまり気にしません。

もちろん、保存されたカウンターを使用してパフォーマンスの向上をアーカイブできる場合もあります。これは典型的なトレードオフです。カウンターを維持すると、挿入と削除のコストがbarはるかに高くなり、カウント クエリが少し安くなります。

したがって、テーブルがめったに変更されず、クエリが頻繁に (たとえば、1 時間に数千回) 実行される場合は、ストアド カウンター プロシージャを使用して実際にパフォーマンスを向上させることができます。ただし、ほとんどの場合、インデックス付きの列を選択し、残りはデータベースに任せます。

于 2013-02-21T08:38:25.063 に答える