MySQL - лучший метод для обработки этих иерархических данных? - PullRequest
5 голосов
/ 29 июня 2010

Это продолжение к:
MySQL - возможно ли получить все подпункты в иерархии?

У меня есть произвольная глубина модель списка смежных таблиц таблица (я нахожусь в точке, где я могу преобразовать ее в модель вложенного множества .

Я прочитал данные MySQL о том, как использовать модель вложенных множеств, хотя казалось, что выполнять основные функции, такие как вставка, обновление и удаление, становится все сложнее и сложнее.

Другой блог, показывающий, как использовать систему триггеров с моделью списка смежности для хранения таблицы предков, которая связывает каждый объект со своими предками.


Прямо сейчас мне нужно иметь возможность вернуть список всех дочерних элементов данного узла, изменить или удалить их. Эта иерархическая структура не будет меняться все время после ее создания, но будет огромное количество иерархических структур.

Три метода, которые я вижу:

  1. Создана хранимая процедура , которая будет выполнять рекурсивный запрос, возвращающий все дочерние элементы.

  2. Преобразовать в модель вложенного набора , которая потребует проникновения в сложности и, возможно, создания хранимой процедуры для добавления, редактирования и удаления в ней.

  3. Создайте таблицу предков , описанную выше для триггеров вставки / удаления для обработки всех данных.

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

Ответы [ 5 ]

4 голосов
/ 02 июля 2010

Quassnoi провел несколько тестов производительности на модели вложенных множеств и модели списка смежности и задокументировал результаты и рекомендации в своем посте в блоге Список смежностей и вложенные множества: MySQL . Исполнительное резюме:

  • Вложенные наборы быстрее выбирают все дочерние узлы или все родительские узлы.
  • Вложенные наборы - плохая идея, если вам часто требуется обновить таблицу.

Вот вывод из его статьи:

В MySQL предпочтительнее использовать модель вложенных множеств, если обновления иерархической структуры нечасты, и можно заблокировать таблицу на время обновления (что может занять минуты на длинной таблице).

Это подразумевает создание таблицы с использованием механизма хранения MyISAM, создание ограничительной рамки типа GEOMETRY, как описано выше, индексацию ее с помощью индекса SPATIAL и сохранение уровня в таблице.

Если обновления таблицы происходят часто или невозможно заблокировать таблицу на длительный период времени, подразумеваемый обновлением, то модель списка смежности должна использоваться для хранения иерархических данных.

Для этого необходимо создать функцию для запроса таблицы.

В остальной части статьи показано, как определить таблицу, реализовать запросы и дать измерения производительности. Использование пространственного индекса является разумной идеей для повышения производительности модели вложенного множества, которая может быть для вас новой.


Если вы также рассматриваете подходы без MySQL, возможно, вы захотите взглянуть на PostgreSQL , которая является другой бесплатной базой данных с открытым исходным кодом. PostgreSQL поддерживает рекурсивные запросы в форме рекурсивных общих табличных выражений , которые упрощают запрос к иерархическим данным, чем в MySQL, а также обеспечивают более высокую производительность. Quassnoi также написал статью Список смежности и вложенные множества: PostgreSQL , в которой показаны детали.

Пока мы говорим о рассмотрении других подходов, база данных Oracle также заслуживает упоминания. У Oracle также есть специальное расширение CONNECT BY, которое делает запрос иерархических данных очень простым и быстрым. Статья Quassnoi Список смежности и вложенные множества: Oracle снова охватывает детали производительности. Запрос, который нужно получить всем детям, чрезвычайно прост в этом случае:

SELECT *
FROM yourtable
START WITH id = 42
CONNECT BY parent = PRIOR id
2 голосов
/ 29 июня 2010

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

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, я не думаю, что он может стать красивее и проще;)

Я понятия не имею о ХранимыхПроцедура способ.Но так как он включает в себя рекурсию (в вашем случае), я не знаю, будет ли это быстро со многими уровнями в иерархии.Я полагаю, вы можете попробовать.

1 голос
/ 07 июля 2010

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

Так как памяти переполняет память (memcache, redis,и т. д.). Для простых разрешений id -> data поиск выполняется намного быстрее, чем SQL, я бы использовал его для кэширования списка идентификаторов прямых дочерних элементов для каждого узла.Таким образом, вы можете получить приличную производительность с помощью рекурсивного алгоритма для построения полного списка для любого узла.

Чтобы добавить / удалить новый узел, вам нужно будет только аннулировать его 'прямой родительский кеш O(1).

Если этого недостаточно, вы можете добавить еще один слой кеша в список всех дочерних узлов каждого узла.Чтобы это работало с прилично изменяемым набором данных, вы должны записать производительность кеша (соотношение свежих / кэшированных обращений) каждого узла и установить уровень допуска для того, когда хранить кеш.Это также может быть сохранено в куче памяти, так как это не жизненно важные данные.

Если вы используете эту более продвинутую модель кэширования, вы должны будете заметить, что эти полные списки дочерних узлов необходимо будет аннулировать, когда любой из нихдети изменены O(log n).

Получив список идентификаторов детей, вы можете использовать синтаксис SQL WHERE id IN( id1, id2, .... ) для запроса того, что вы хотите.

1 голос
/ 02 июля 2010

Возможно, вам следует рассмотреть возможность использования баз данных, ориентированных на документы, таких как MongoDB .Это может сделать вашу жизнь намного проще.

0 голосов
/ 02 июля 2010

Мне когда-то приходилось хранить сложную иерархическую систему спецификаций произвольной глубины в SQL-подобном менеджере баз данных, который на самом деле не соответствовал задаче, и в итоге это приводило к запутанным и хитрым указаниям, определениям данных,запросы и т. д. После перезапуска с нуля, использования менеджера БД для предоставления только API для чтения и записи записей по простым индексированным ключам и выполнения всего фактического ввода / манипуляции / создания отчетов во внешнем коде, конечный результат был быстрее реализован, легче понять, и проще в обслуживании и совершенствовании.Самым сложным запросом, по сути, был SELECT A FROM B.

Итак, вместо того, чтобы встраивать логику и операции в ограничения MySQL, рассмотрите возможность выкручивания кода, чтобы делать то, что вы хотите, и полагаться на MySQL только для самых низких-уровень получает / ставит.

...