Участник:ArmorAdmin/Дерево в БД — различия между версиями
м (→Дерево в БД) |
|||
Строка 26: | Строка 26: | ||
Два дополнительных поля дают широкие возможности манипуляции данными с использованием простых запросов. Правда, на стороне клиента надо сделать несколько вариантов обработки, но производительность при этом нас не озадачивает. | Два дополнительных поля дают широкие возможности манипуляции данными с использованием простых запросов. Правда, на стороне клиента надо сделать несколько вариантов обработки, но производительность при этом нас не озадачивает. | ||
− | Если SQL-запросом необходимо выбрать ветку для заданного корня | + | Если SQL-запросом необходимо выбрать ветку для заданного корня ID=5, то это делается так: |
<code>where root=5</code> | <code>where root=5</code> | ||
Строка 32: | Строка 32: | ||
В этом случае выстроить дерево на клиенте — дело техники (по связке ID, PID или по path), при этом сервер не нагружен. | В этом случае выстроить дерево на клиенте — дело техники (по связке ID, PID или по path), при этом сервер не нагружен. | ||
− | Если нужно выбрать дерево | + | Если нужно выбрать дерево для десяти корневых сообщений — выборка с <code>PID = -1</code> и <code>LIMIT 10</code>, по каждому дополнительный запрос как в предыдущем варианте. Т.е. число запросов получается не по количеству сообщений в дереве, а по числу корневых сообщений + 1. |
Самое хитрое — выборка части дерева не с корня, например для узла "5.12.33". | Самое хитрое — выборка части дерева не с корня, например для узла "5.12.33". |
Версия 10:03, 12 июля 2007
Дерево в БД
- Автор(ы): --Чобиток Василий 14:21, 11 июля 2007 (EEST)
В компьютерных программах часто используется древовидное представление данных (например, в древовидном представлении очень удобно просматривать ход обсуждения какой-либо темы в процессе переписки или на форуме).
Как правило, хранение данных, имеющих древовидную структуру, организовывается в реляционной СУБД с использованием двух ключевых полей — первичного уникального ключа (обозначим его ID) и вторичного (PID), ссылающегося на ID ближайшего узла верхнего уровня (родителя). Если текущий узел корневой, в зависимости от реализации PID может быть равен -1, 0 или null.
Если дерево небольшое, хранится в отдельной таблице и используется целиком (как правило такой вариант используется в вертикальном меню некоторых программ), то связка ID-PID прекрасно работает. Если же объём данных составляет десятки и сотни тысяч записей, а выбирать необходимо только какую-то часть дерева, тогда возникают проблемы с производительностью — для выборки дерева из БД по связке ID-PID необходимо рекурсивно выполнить большое число SQL-запросов, что сильно нагружает сервер, или одним запросом выбрать все дерево и на сервере или клиенте программно отсечь лишние данные и построить дерево, что тоже очень затратно с точки зрения нагрузки на сервер.
Рассмотрим возможный вариант решения проблемы.
Допустим, что в нашем случае для корневых узлов PID = -1.
Дополнительно вводим:
- индексированное поле rootID, которое ссылается на корневое сообщение ветки;
- и текстовое уникальное индексированное поле path.
Следует заметить, что некоторые СУБД позволяют заводить текстовое поля практически без ограничения длины с возможностью их индексации, как это принято для строковых полей ограниченной длины. Если у нас такая СУБД, то path следует проиндексировать.
Итак, поле path. В нем через точку вписаны ID всех узлов, начиная с root, для которых он является вложенным, включая ID самого узла, например так: "2.34.456".
Два дополнительных поля дают широкие возможности манипуляции данными с использованием простых запросов. Правда, на стороне клиента надо сделать несколько вариантов обработки, но производительность при этом нас не озадачивает.
Если SQL-запросом необходимо выбрать ветку для заданного корня ID=5, то это делается так:
where root=5
В этом случае выстроить дерево на клиенте — дело техники (по связке ID, PID или по path), при этом сервер не нагружен.
Если нужно выбрать дерево для десяти корневых сообщений — выборка с PID = -1
и LIMIT 10
, по каждому дополнительный запрос как в предыдущем варианте. Т.е. число запросов получается не по количеству сообщений в дереве, а по числу корневых сообщений + 1.
Самое хитрое — выборка части дерева не с корня, например для узла "5.12.33".
Можно просто выбирать:
where path like '5.12.33.%'
(обратите внимание на точку, добавленную к коду перед знаком процента, без нее могут быть выбраны и записи с кодом "5.12.333", не имеющие отношения к нашей ветке)
поскольку поле проиндексировано, то для начала строки индекс отработает. Если с индексом по длинному тексту проблема, возможен такой вариант:
where root = 5 and path like '5.12.33.%'
При правильном оптимизаторе отработает выборка по проиндексированному root, после чего уже по ограниченному набору данных будет происходить like.