особенности MySQL запросов
Однажды мне понадобилось собрать информацию о всех родительских категориях для текущей (ну типа определить путь от корня до текущей категории). Мне известен только идентификатор текущей категории. Долго думал, как мне такой лихой запрос составить. Не придумал, поэтому решил делать как положенно - т.е. в цикле выбирать родительские категории, пока не дойду до корня. Но всё делать на PHP мне не захотелось, поэтому я покопался в книжке по MySQL и нашёл там "переменные", с помощью которых всё и сделал.
Всё бы ничего, да только совершенно неожиданно я столкнулся с интересным явлением, который объяснить не смог. Может вы мне разъясните, что да как??
Вот запрос:
SET @prev_cat=CATEGORY_IDENTIFICATOR;
SELECT g.id AS cid,g.type,@prev_cat:=g.parentid AS parentid,g.name,g.gdescr FROM gds_tree g WHERE g.id=@prev_cat;
Он должен мне возвращать данные о категории с id=CATEGORY_IDENTIFICATOR и устанавливать @prev_cat в идентификатор "родительской" категории. Он так и делает, но только, если в таблице "gds_tree" более одной записи (ну т.е. категории) - всё работает нормально.
А вот если в таблице "gds_tree" ровно одна категория (т.е. запись), то этот запрос мне всегда возвращает эту запись, вне зависимости от того, что я подставляю в CATEGORY_IDENTIFICATOR. На практике это вылилось в зависание скрипта с линейным ростом требуемой памяти. А так как на работе админ зачем-то установил время выполнения PHP-скриптов !!5 МИНУТ!!, было очень весело сидеть и смотреть на красную лампочку (индикатор занятости винта) на серверном компе ;)
Способ прост и гениален. Получить всё дерево одним запросом -- не вопрос. И никакой рекурсии.
Лично я, давно уже отошел от рекурсивного хранения деревьев и пользую nested sets во всех задачах -- пока минусов не вижу.
В общем, всем искренне рекоммендую.
Ссылки по теме:
По русски с картинками
PEAR класс для работы с n.s. -- очень удобный
Ссылки по теме:
По русски с картинками
PEAR класс для работы с n.s. -- очень удобный
Сэнкс за линки.
Вот до чего доводят всякие хтмлы и языки высокого уровня - до полной деградации программистов. Совсем я чё-то про оптимизацию забыл. Так скоро заного в школу идти придётся :)
Кстати в этом методе "Nested Set" есть один большой минус - это добавление новых данных или изменение структуры. Конечно в большинстве случаев (и в моём тоже) добавление происходит довольно редко. Но вот если придётся писать какую ни будь "барахолку", где и структура изменяемая и данные каждый юзер может добавлять, вот там начнётся боольшааяя тормозуха.
Вобщем есть над чем подумать.
Может я скоро новый способ хранения дерева в БД придумаю ;)
.....
Кстати в этом методе "Nested Set" есть один большой минус - это добавление новых данных или изменение структуры. Конечно в большинстве случаев (и в моём тоже) добавление происходит довольно редко. Но вот если придётся писать какую ни будь "барахолку", где и структура изменяемая и данные каждый юзер может добавлять, вот там начнётся боольшааяя тормозуха.
...
Ну... Если немножко поDOOMать, обходится это дело совершенно без "тормозух" :)
Скажем так, для каждого трэда, как бы начинать новую "вершину" и работать только от неё. Тогда апдэйтить придется только 1 ветку а не всё дерево.
Кстати, в одном проекте по управлению контентом, мне нужно было решить задачу хранения сложной структуры документа. Так вот я там использовал n.s. заводя по "вершине" для каждого документа. Работало влёт, реализовывалось просто, а документ, при этом, получал абсолютно ничем не огранинченую структуру.
Кстати, ещё один как бы совет.
Если у тебя сильно ветвистая структура, имеет смысл отдельно хранить дерево в полностью проиндексированной таблице с одними интами а контент разнести в другие таблицы и цеплять их по мере надобности. Тогда ещё шустрее работает.
В PEAR так и сделано по моему.
Да и вообще... С веб проектами содержашими более полумиллиона записей в бд мне приходилось сталкиваться всего пару раз за всю свою практику. А на меньших объёмах затормозить базу можно только очень-очень кривыми лапками :)