Реализация иерархической структуры данных в базе данных
Я знаю, что есть два подхода: список смежности и вложенное дерево. Он сказал, что список смежности может стать медленным для использования при обходах из-за многочисленных запросов. Но я не знаю никаких реалистичных цифр для этого. Сайт, который я создаю, будет иметь в области 200 страниц. Является ли обход для генерации (например) карты сайта, которая займет больше 0,3 секунды?
Работа с MySQL (innoDB) с использованием стека LAMP.
Я предпочел бы реализовать смежность, если возможно, из-за более упрощенного дизайна.
Спасибо.
Ответы
Ответ 1
Есть больше вариантов, чем только вы упомянули. Есть:
- Список контактов ( "parent_id", который используется почти всеми)
- Вложенные наборы
- Перечисление пути
- Таблица закрытия (aka Adjacency Relation)
См. мой ответ на "Каков наиболее эффективный/элегантный способ разобрать плоскую таблицу в дерево?"
Или несколько книг:
Ответ 2
В статье Управление иерархическими данными в MySQL подробно описано.
Я бы рекомендовал метод "вложенного набора", так как он позволяет получить все дерево (и его дочерние элементы) в одном запросе. В основном чтение дешево, но записи дороги, потому что все дерево нужно перебалансировать. Но в тех случаях, когда вы читаете 99%, тогда это полностью оправдано.
Ответ 3
Наивный подход к разбору списка смежности требует большого количества запросов, а для больших списков может потребоваться значительное количество времени для создания в памяти. Для справки, наивный подход, к которому я имею в виду, можно суммировать как: Выбрать все элементы без родителя, Затем для каждого элемента рекурсивно получить его детьми. Для этого подхода требуется n + 1 запросов к базе данных.
Я использовал следующий подход для создания списка смежности с 1 запросом. Выберите все элементы из базы данных. Перенесите все элементы в массив, проиндексированный их ключом. Пройдите массив и назначьте ссылку от родительского объекта каждому из этих детей. Перейдите к массиву второй раз и удалите все дочерние объекты, оставив только объекты корневого уровня.
Поскольку вы упомянули стек LAMP, код PHP для этого примерно выглядит следующим образом:
<?php
// Assumes $src is the array if items from the database.
$tmp = array();
// Traverse the array and index it by id, ensuing each item has an empty array of children.
foreach ($src as $item) {
$item['children'] = array();
$tmp[$item['id']] = $item;
}
// Now traverse the array a second time and link children to their parents.
foreach ($tmp as $id => $item) {
if ($item['parent_id'] != 0 || $item['parent_id'] !== NULL) {
$tmp[$item['parent_id']]['children'][$id] = &$tmp[$id];
}
}
// Finally create an array with just root level items.
$tree = array();
foreach ($tmp as $id => $item) {
if ($item['parent_id'] == 0 || $item['parent_id'] === NULL) {
$tree[$id] = $item;
}
}
// $tree now contains our adjacency list in tree form.
?>
Обратите внимание, что этот код предназначен для иллюстрации метода построения списка смежности из одного запроса к базе данных. Вероятно, он может быть оптимизирован для меньшего потребления памяти и т.д. Он также не был протестирован.
Джим
Ответ 4
Вот несколько вопросов, которые могут вам помочь:
SQL, как хранить и перемещаться по иерархиям
Какая лучшая схема базы данных для моей навигации
Ответ 5
Другой подход называется "вложенным множеством", я думаю, не "вложенным деревом".
В любом случае, хорошая карта сайта - это то, что вы можете узнать ее максимальную глубину. Я думаю, что проблема с моделью смежности заключается в том, что соответствующий SQL работает на одном уровне за раз, поэтому, если у вас есть уровни "n" , тогда вам нужен цикл "n" SQL-операторов... но я думаю (я ' m not sure), что, если вы заранее знаете "n" , вы можете запрограммировать соответствующий SQL-номер с фиксированным числом и несколькими уровнями.
0,3 секунды звучит для меня как очень долгое время, чтобы изобразить 200 страниц, так что, возможно, ОК.
Также карта сайта не обновляется очень часто; поэтому, даже если это займет много времени, чтобы извлечь из SQL, вы, вероятно, можете кэшировать извлеченное/вычисленное дерево в ОЗУ.
Альтернативно вместо того, чтобы беспокоиться о SQL для построения дерева, вы можете просто сохранить его как можно проще (как список смежности), извлечь его из базы данных в виде простого набора строк и построить дерево в ОЗУ ( используя циклы на языке программирования высокого уровня) вместо использования циклов в SQL для построения дерева с помощью операторов SQL.
Ответ 6
Для полноты: Oracle имеет операторы START_WITH
и CONNECT_BY
: см. этот Иерархические запросы.