Иерархические данные SQL (рекурсивный CTE vs HierarchyID vs таблица закрытия)

у меня есть набор иерархических данных, используемых в базе данных SQL Server. Данные хранятся с идентификатором guid в качестве первичного ключа и parentGuid в качестве внешнего ключа, указывающего на объекты непосредственного родителя. Я чаще всего получаю доступ к данным через Entity Framework в проекте WebApi. Чтобы сделать ситуацию немного сложнее, мне также нужно управлять разрешением на основе этой иерархии так, чтобы разрешение, примененное к родителю, применялось ко всем его потомкам. Мой вопрос это:

Я искал повсюду и не могу решить, что лучше справиться с этой ситуацией. Я знаю, что у меня есть следующие варианты.

  1. я могу создать Recursive CTEs, общее табличное выражение, (он же RCTE) для обработки иерархических данных. Это кажется самым простым подходом для обычного доступа, но я беспокоюсь, что он может быть медленным при использовании для определения уровней разрешений для дочерних объектов.
  2. я могу создать hierarchyId поле Тип данных в таблице и используйте предоставляемые SQL Server функции, такие как GetAncestor(), IsDescendantOf() и т. д. Это похоже на то, что это сделает запрос довольно легким, но, похоже, требует довольно сложного триггера вставки/обновления, чтобы сохранить поле hierarchyId правильным через вставки и перемещения
  3. я могу создать closure table, который будет хранить все связи в таблице. Я представляю себе это как таковое: Родительский столбец и дочерний столбец, каждая связь родитель -> ребенок будет представлена. (ie 1 - >2 2 - >3 будет представлен в базы данных как 1-2, 1-3, 2-3). Недостатком является то, что для этого требуются триггеры insert, update и delete, хотя они довольно просты, и этот метод генерирует много записей.

Я пробовал искать повсюду и не могу найти ничего, дающего какие-либо советы между этими тремя методами.

PS Я также открыт для любых альтернативных решений этой проблемы

1 ответов


Я использовал все три метода. Это в основном вопрос вкуса.

Я согласен, что иерархия с отношениями родитель-потомок в таблице является самой простой. Перемещение поддерева просто, и легко закодировать рекурсивный доступ с помощью CTEs. Производительность будет проблемой, только если у вас очень большие древовидные структуры и вы часто обращаетесь к иерархическим данным. По большей части рекурсивные CTEs очень быстры, когда у вас есть правильные индексы на таблица.

таблица закрытия больше похожа на дополнение к вышесказанному. Поиск всех потомков данного узла происходит молниеносно, вам не нужны CTEs, только одно дополнительное соединение, поэтому это сладко. Да, количество записей взрывается, но я думаю, что это не более чем N-1 раз количество узлов для дерева глубины N (например, третичное дерево глубины 5 потребует 1 + 3 + 9 + 27 + 81 = 121 соединения при сохранении только отношения родитель-потомок против 1 + 3 + (9 * 2) + (27 * 3) + (81 * 4) = 427 для таблицы закрытия). Кроме того, записи таблицы закрытия настолько узки (как минимум 2 ints), что они почти не занимают места. Создание списка записей для вставки в таблицу закрытия при вставке новой записи в иерархию требует незначительных затрат.

Мне лично нравится HierarchyId, так как он действительно сочетает в себе преимущество вышеупомянутых двух, что является компактным хранилищем и молниеносным доступом. Как только вы получите его настроить, легко и запросов занимает очень мало места. Как вы упомянули, немного сложно перемещать поддеревья, но это управляемо. В любом случае, как часто вы действительно перемещаете поддерево в иерархии? Есть некоторые ссылки, которые вы можете найти, которые предложат некоторые методы, например:

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

основным недостатком, который я нашел в hierarchyId, является кривая обучения. Не так очевидно, как работать с ним, как с двумя другими методами. Я работал с некоторыми очень яркими разработчиками SQL, которые часто зацеплялись за него, поэтому вы в конечном итоге получаете одного или двух экспертов-резидентов, которые должны задавать вопросы от всех остальных.