3

次の場合を考えてみてください(質問のために簡略化されています)。

SQLServer2012データベースには次のテーブルがあります。

Parent_Table

Id  | Parent table fields
----+--------------------
1   | ...
2   | ...
3   | ...
...

Child_Table

Id  | ParentId | Child table fields
----+----------+-------------------
1   | 2        | ...
2   | 1        | ...
3   | 1        | ...
4   | 3        | ...
5   | 2        | ...
...

Big_Table

Id      | ChildId  | Value  | Status  | Other fields
--------+----------+--------|---------------------
1       | 12       | 672    | Closed  |
2       | 23       | 133    | Closed  |
3       | 7        | 2611   | Open    |
4       | 14       | 84     | Closed  |
...
1295769 | 23       | 458    | Closed  |
1295770 | 18       | 1046   | Open    |
1295771 | 7        | 8      | Open    |

子テーブルと親テーブルは比較的小さく(親ごとに約100個の親エントリと5個の子エントリ)、それらのエントリは1日に数回だけ挿入または削除されます。

一方、「ビッグテーブル」は急速に成長しており(議論のために毎秒100エントリ)、しばらくすると行のステータスがクローズになります(クライアントセッションを考えてみてください。これは実際にはここにあります)。 )。

定期的に(数秒ごとに)指定されたParent.IdのBig_Table行の数とBig_Table.Value列の合計を提供する必要があります-毎回異なるものです。

単純な実装(内部結合などを使用)は非常に非効率的である可能性があり、より良いソリューションには追加のテーブル、ある種のカウンターのテーブルが含まれる可能性があります。または、これをサービスコード(?!)に実装して注意する必要があります。どういうわけか永続性の。

上記を実装するための「正しい」(効率面での)方法は何でしょうか?親/子の追加レベルを処理するソリューションが最適です。

4

2 に答える 2

3

ChildIdが常に同じParentIdを保持していると仮定した場合、考慮すべき1つのオプションは、ParentIdをBig_Tableに追加することです。特定の行が、制御するアプリケーションコードからのみこれらのテーブルに追加されることが確実な場合(たとえば、INSERTステートメント自体を実行するデータベース接続を持つユーザーとは対照的に)、親テーブルと子テーブルのキャッシュをメモリに保持し、 Big_Tableに挿入するときに、ChildIdからParentIdへのクイックマッピングを提供します。その場合、合計/カウントのクエリは完全にBig_Tableでのみ実行されます。もちろん、この非正規化によりBig_Tableのサイズが大きくなりますが、それとアプリケーションの変更が許容できる場合は、これが実行可能なオプションです。

さらに、ParentIdがBig_Tableの行(またはパフォーマンスが最も懸念される行)にアクセスする主な方法である場合は、ParentIdでBig_Tableをパーティション化することを検討できます。

まったく異なるアプローチは、必要な統計をParent_Tableに直接保存し、Big_Tableでトリガーを使用して更新を維持するか、アプリケーションコードですべてのデータベースの相互作用を制御する場合は、アプリケーションロジックを使用して統計を更新することです。 Big_Table挿入。一貫性を確保するためにこのトランザクション内で実行できます。または、何らかのエラーに耐えられる場合は、非同期の統計更新として実行できるため、統計がバックグラウンドで更新されている間、Big_Tableへの挿入をすばやく行うことができます。

親と子の追加レベルの処理に関しては、柔軟性と効率のどちらかを選択する必要があるかもしれません。たとえば、パフォーマンスを向上させるために深度ロジックをハードコーディングするために、サポートするツリーの深度を制限する必要がある場合があります。

于 2012-11-10T00:23:53.490 に答える
1

私は以下の2で時間テストを行います、それが合理的であるならば、あなたはそれを単純に保つことができます。with(nolock)ヒントが状況(データベース設定、データの性質)に適しているかどうかを判断するのはあなたに任せます。親IDがわかっているので、Parent_Tableを含める必要はありません。

明らかに、Big_Table.ChildIdとChild_Table.ParentIdにインデックスが必要です。

select sum(Value)
from Big_Table with(nolock)
where ChildId in
(select Id
from Child_Table with(nolock)
where ParentId = @ParentId)

select sum(Value)
from Big_Table with(nolock)
inner join Child_Table with(nolock)
on  Big_Table.ChildId = Child_Table.Id
where Child_Table.ParentId = @ParentId
于 2012-11-10T00:42:01.680 に答える