6

これは次のフォローアップです:MySQL-
階層内のすべてのサブアイテムを取得することは可能ですか?

任意の深さの隣接リストモデルテーブルがあります(ネストされたセットモデルに変換できるようになりました) 。

入れ子集合モデルの使用方法に関するMySQLデータを読みましたが、挿入、更新、削除などの基本的な機能を実行するのはますます複雑になり、非常に複雑になっているようです。

隣接リストモデルでトリガーシステムを使用して、各オブジェクトをその祖先に関連付ける祖先のテーブルを保持する方法を示す別のブログ。


今のところ、特定のノードのすべての子のリストを返して、それらを変更または削除できるようにする必要があります。この階層構造は、一度作成されると常に変更されるわけではありませんが、大量の階層構造が存在します。

私が見る3つの方法は次のとおりです。

  1. すべての子を返す再帰クエリを実行するストアドプロシージャを作成しました。

  2. 入れ子集合モデルに変換します。これには、複雑さを理解し、その中で追加、編集、削除するためのストアドプロシージャを作成する必要があります。

  3. すべてのデータを処理するために、挿入/削除トリガーで上記の祖先テーブルを作成します。

私が検討していない他の方法がある場合は、私に知らせてください。このリストを更新します。

4

5 に答える 5

4

Quassnoiは、ネストされたセットモデルと隣接リストモデルでいくつかのパフォーマンステストを実行し、その結果と推奨事項を彼のブログ投稿「隣接リストとネストされたセット:MySQL 」に文書化しました。エグゼクティブサマリーは次のとおりです。

  • ネストされたセットは、すべての子ノードまたはすべての親ノードをフェッチする場合に高速です。
  • テーブルを頻繁に更新する必要がある場合は、ネストされたセットはお勧めできません。

彼の記事からの結論は次のとおりです。

MySQLでは、階層構造の更新が頻繁ではなく、更新中(長いテーブルでは数分かかる場合があります)テーブルをロックするのが手頃な場合は、入れ子集合モデルを優先する必要があります。

これは、MyISAMストレージエンジンを使用してテーブルを作成し、上記のようにGEOMETRYタイプのバウンディングボックスを作成し、SPATIALインデックスを使用してインデックスを作成し、テーブル内のレベルを永続化することを意味します。

テーブルの更新が頻繁に行われる場合、または更新によって暗示される長期間テーブルをロックすることができない場合は、隣接リストモデルを使用して階層データを格納する必要があります。

これには、テーブルをクエリする関数を作成する必要があります。

この記事の残りの部分では、テーブルを定義し、クエリを実装し、パフォーマンスを測定する方法を示します。空間インデックスの使用は、あなたにとって新しいかもしれない入れ子集合モデルのパフォーマンスを改善するための賢いアイデアです。


MySQLを使用しないアプローチも検討している場合は、別の無料のオープンソースデータベースであるPostgreSQLを検討することをお勧めします。PostgreSQLは、再帰共通テーブル式の形式で再帰クエリをサポートします。これにより、MySQLよりも階層データのクエリが簡単になり、パフォーマンスも向上します。Quassnoiは、詳細を示す「隣接リストと入れ子集合:PostgreSQL」という記事も書いています。

他のアプローチを検討している間、Oracleのデータベースも言及する価値があります。CONNECT BYOracleには、階層データのクエリを非常に簡単かつ高速にするカスタム拡張機能もあります。Quassnoiの記事隣接リストとネストされたセット:Oracleがパフォーマンスの詳細を再びカバーしています。この場合、すべての子を取得するために必要なクエリは非常に単純です。

SELECT *
FROM yourtable
START WITH id = 42
CONNECT BY parent = PRIOR id
于 2010-07-01T23:38:24.780 に答える
2

せん断の単純さと利便性のために、私は常にネストされたセットを使用します。私はいつもこの記事を提案します。このような階層データを使用する作業に必要なクエリが優れていることを示しています。ここで見られる唯一の欠点は、階層が特定のレベルの複雑さに達したときに新しいレコードの挿入/更新が遅くなる可能性があることですが、読み取りは私が見た他の多くのソリューションよりも高速です。

上記の記事の例を挙げてみましょう。

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
WHERE t1.name = 'ELECTRONICS';

+-------------+----------------------+--------------+-------+
| lev1        | lev2                 | lev3         | lev4  |
+-------------+----------------------+--------------+-------+
| ELECTRONICS | TELEVISIONS          | TUBE         | NULL  |
| ELECTRONICS | TELEVISIONS          | LCD          | NULL  |
| ELECTRONICS | TELEVISIONS          | PLASMA       | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS  | FLASH |
| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS   | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL  |
+-------------+----------------------+--------------+-------+
6 rows in set (0.00 sec)

SQLに関しては、もっと美しくシンプルになるとは思いません;)

ストアドプロシージャの方法がわかりません。しかし、それは(あなたの場合)再帰を伴うので、階層内の多くのレベルで高速になるかどうかはわかりません。ぜひお試しください。

于 2010-06-29T05:56:35.467 に答える
1

たぶん、 MongoDBのようなドキュメント指向データベースの使用を検討する必要があります。それはあなたの人生をずっと楽にするかもしれません。

于 2010-07-02T00:01:32.267 に答える
1

階層データセットを扱うときは、キャッシュを念頭に置いてアプローチするのが最善だと思います。この問題にこのように対処するこの方法の主な利点の1つは、データベースを変更するのが難しい可能性のあるものに非正規化する必要がないことです。

メモリヒープ(memcache、redisなど)のルックアップは、単純な解決のためにSQLよりもはるかに高速でid -> dataあるため、各ノードの直接の子のIDのリストをキャッシュするためにそれらを使用します。このようにして、再帰的アルゴリズムを介して適切なパフォーマンスを取得し、任意のノードの完全なリストを作成できます。

新しいノードを追加/削除するには、その直接の親キャッシュを無効にするだけで済みますO(1)

それが十分に速くない場合は、各ノードのノードのすべての子のリストにキャッシュの別のレイヤーを追加できます。これが適切に変更可能なデータセットで機能するためには、各ノードのキャッシュパフォーマンス(フレッシュ/キャッシュヒットの比率)を記録し、キャッシュを保存するタイミングの許容レベルを設定する必要があります。これは重要ではないデータであるため、メモリヒープに保存することもできます。

このより高度なキャッシュモデルを使用する場合は、子のいずれかが変更されたときに、これらの完全な子ノードリストを無効にする必要があることに注意する必要がありますO(log n)

子IDのリストを取得したら、SQLのWHERE id IN( id1, id2, .... )構文を使用して必要なものを照会できます。

于 2010-07-07T00:29:17.167 に答える
0

私はかつて、複雑な階層型の任意の深さの部品表システムをSQLのようなデータベースマネージャーに格納する必要がありましたが、それは実際にはタスクに対応していませんでした。 。最初から再起動し、db managerを使用して単純なインデックス付きキーのレコード読み取りと書き込み用のAPIのみを提供し、外部コードで実際の入力/操作/レポートをすべて実行した後、最終結果は実装が迅速になり、理解し、保守と強化が簡単になります。必要な最も複雑なクエリは、基本的にSELECT AFROMBでした。

したがって、MySQLの制限内にロジックと操作を埋め込むのではなく、コードを実行して必要な処理を実行し、最低レベルの取得/出力のみをMySQLに依存することを検討してください。

于 2010-07-02T01:23:56.623 に答える