21

SQL Server データベースで使用されている一連の階層データがあります。データは guid を主キーとして格納され、parentGuid はオブジェクトの直接の親を指す外部キーとして格納されます。WebApi プロジェクトの Entity Framework を介して最も頻繁にデータにアクセスします。状況をもう少し複雑にするために、親に適用されるアクセス許可がそのすべての子孫に適用されるように、この階層に基づいてアクセス許可を管理する必要もあります。私の質問はこれです:

私はあちこちを検索しましたが、この状況を処理するのに最適な方法を判断できません。次のオプションがあることを知っています。

  1. Recursive CTEs階層データを処理するために、Common Table Expression (別名 RCTE) を作成できます。これは通常のアクセスでは最も単純なアプローチのようですが、子オブジェクトのアクセス許可レベルを決定するために使用すると遅くなる可能性があるのではないかと心配しています。
  2. テーブルにデータ型フィールドを作成し、hierarchyIdSQL Server が提供するGetAncestor()IsDescendantOf()、などの関数を使用できます。これによりクエリがかなり簡単になるようですが、hierarchyId フィールドを正しく維持するには、かなり複雑な挿入/更新トリガーが必要になるようです。インサートとムーブを通して
  3. closure tableすべてのリレーションシップをテーブルに格納する を作成できます。私はそれを次のように想像しています:親列と子列、それぞれの親 - >子関係が表されます。(つまり、1->2 2->3 は、データベースでは 1-2、1-3、2-3 として表されます)。欠点は、挿入、更新、および削除のトリガーがかなり単純であるにもかかわらず必要であり、この方法では大量のレコードが生成されることです。

私はあちこち検索してみましたが、これら3つの方法の間でアドバイスを与えるものは何も見つかりません.

PS私はまた、この問題に対する代替ソリューションを受け入れます

4

1 に答える 1

15

私は3つの方法すべてを使用しました。それは主に味の問題です。

テーブル内の親子関係を持つ階層が最も単純であることに同意します。サブツリーの移動は簡単で、CTE を使用して再帰アクセスを簡単にコーディングできます。非常に大きなツリー構造があり、階層データに頻繁にアクセスしている場合にのみ、パフォーマンスが問題になります。ほとんどの場合、テーブルに正しいインデックスがある場合、再帰 CTE は非常に高速です。

閉鎖テーブルは、上記の補足のようなものです。特定のノードのすべての子孫を見つけるのは非常に高速です。CTE は必要ありません。追加の結合が 1 つあるだけなので、便利です。はい、レコードの数は爆発しますが、深さ N のツリーのノード数の N-1 倍以下だと思います (たとえば、深さ 5 の 3 次ツリーには 1 + 3 + 9 + 27 + 81 が必要です) = 121 接続 (親子関係のみを格納する場合) 対 1 + 3 + (9 * 2) + (27 * 3) + (81 * 4) = 427 (閉鎖テーブルの場合)。さらに、クロージャー テーブル レコードは非常に狭いため (最小でわずか 2 int)、スペースをほとんど占有しません。新しいレコードが階層に挿入されるときにクロージャ テーブルに挿入するレコードのリストを生成するには、わずかなオーバーヘッドがかかります。

個人的には HierarchyId が気に入っています。なぜなら、コンパクトなストレージと超高速アクセスという上記 2 つの利点を実際に組み合わせているからです。セットアップが完了すると、クエリが簡単になり、スペースもほとんど必要ありません。あなたが言ったように、サブツリーを移動するのは少し難しいですが、扱いやすいです。とにかく、実際に階層内のサブツリーをどのくらいの頻度で移動しますか? いくつかの方法を提案するリンクがいくつかあります。

http://sqlblogcasts.com/blogs/simons/archive/2008/03/31/SQL-Server-2008---HierarchyId---How-do-you-move-nodes-subtrees-around.aspx

hierarchyId の主な欠点は学習曲線です。他の 2 つの方法ほど明確ではありません。私は非常に優秀な SQL 開発者と仕事をしたことがありますが、彼らは頻繁にそれに引っ掛かります。

于 2013-06-25T21:44:15.597 に答える