Как стать автором
Обновить

Комментарии 47

честно — а если переписать это с T-SQL на какой-нибудь нормальный язык, хотя бы на Java — не будет ли короче, понятнее и быстрее?
т.е. понятно, что потребуются какие-нибудь инфраструктурные изменения, но СУБД h2database.com, например, предлагает писать триггеры не на SQL, а на Java, в любой современной невероятно удобной IDE.

А если и само приложение вдруг на Java, то такая связка будет работать _удивительно_ быстро из-за отсутствия межпроцессного взаимодействия.

// Нисколько не хочу обидеть MySQL + PHP. Наоборот, поздравляю с новым оператором goto =)
Немного не понимаю какое ограничение может наложить использование триггеров написаных на Java.
Не вижу никаких сложностей.
doc.prototypes.ru/database/nestedsets/theory/
Есть определенная последовательность действий, которую я отработал еще 4 года назад.
А на каком уровне это реализовать и с помощью какого языка — вопрос исключительно религии разработчика ;-).
Интересно при чем тут PHP?

Вопрос к автору (предыдущую статью не читал), а зачем этот гемор? По сути Nested Sets используется в тех случаях где изменения дерева происходят не часто, как по мне то использование триггеров в данном случае излишне…

Но за проделанную работу(код) спасибо, мало какие задачи встретятся…
Что лучше, держать этот геморрой у себя в приложении или прицепить этот триггер на таблицу в которой у нас дерево и забыть об этой болезни как о страшном сне?
Для уровня приложений у я использовал инструмент, который универсален для любой таблицы, но любая универсальность — это более сложная логика работы.

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

Не представляешь как удобно теперь с таким деревом в консольке работать.
На PHP NestedSets у меня заняло 25 строк. Ваше решение читать и понимать сложновато. Хотя некоторые преимущества, безусловно, присутствуют.
Вообще, я бы предложил таки посмотреть код и понять, что там происходит, но вкратце, объясню.
Большую часть кода триггер вычисляет координаты, т.к. решение смешанное, то в качестве конечной координаты может быть parent_id, как в рекурсивных деревьях, так и left_key для деревьев Nested Sets. Отсюда немного усложненная логика вычисления координат.
При известных координатах вообще-то достаточно двух запросов для каждого из действий. Причем для перемещения, реально выполняется только один запрос обновления, а два их только потому, что они разные для направления перемещения.
Ну написать один раз класс для работы с Nested Sets и потом использовать для любой таблицы…
Вопрос в том, что при использовании разных framework с разными «обертками» работы с БД этот класс придется постоянно перестраивать, если он будет участвовать в цепочке наследования или как плагин.
При работе с несколькими языками программирования — то же самое.
Еще раз повторюсь.
Я до недавнего времени использовал подобные классы как плагины, но я посчитал, что перевод этого алгоритма на более низкий уровень более оправдано, ввиду использования в работе новых технологий.
1. Короче не будет, понятнее будет еще меньше. Как раз цель в данном случае убрать вообще все непонятные действия с глаз долой, и работать без них.
2. Для Java решения нет, т.к. с ней не работал и надобности не было. Но есть решения для других языков:
Решение для Perl — phoinix.ucoz.ru/publ/5
Решение для PHP — phoinix.ucoz.ru/publ/6 (правда не до конца дописано, ввиду практической не надобности мне);

Была, конечно идея сделать модули не как додлнительный внешний инструментарий, а как встраиваемый, как прослойка интерфейсов («оберток») для работы с БД. Но таких «оберток» много больше и для каждой обертки делать решение — мягко скажем не рационально, а вот типов БД не так много, поэтому, ИМХО лучше эти вопросы решать на более низком уровне.
Причем тут T-SQL?
Насколько я помню, T-SQL — процедурный диалект в MSSQL, то, что в MySQL, называется SQL/PSM, не?
Это ипостаси одной и той же сущности, так же как и PL/SQL.
Имеющие разный синтаксис и реализацию… и если уж написано на какойто конкретной ипостаси то нужно про нее и вести разговор… SQL/PSM это вродебы больше к PostgreSQL имеет отношение
SQL/PSM — это диалект, рекомендованный в стандарте SQL2003, к постгресу на данный момент отношения никакого не имеет, а вот в MySQL именно он и реализован. У постгреса PL/PgSQL, скопированный, очевидно, с ораклового PL/SQL, у которого, в свою очередь, родословная идет от Ады.
Перед тем как писать хранимку стоит хорошо подумать, возможно решение на уровне приложения будет проще, и потери в скорости не будут критическими.
Этим решениям этим летом исполнилось 4 года. (http://phoinix.ucoz.ru/publ/7)
Сейчас мне захотелось их развить.
Тем более что 4 года назад триггеров в MySQL не было, как и хранимых процедур. Были только зачатки в 4-й не особо стабильной версии.
Через пять лет после имплементации nested sets я пришел к выводу, что реляционные базы данных плохо подходят для хранения иерархических структур. Кроме того, я ни разу не видел, реальной необходимости в nested sets, кроме как в академических задачах(более 500 уровней и миллионы узлов). Для всего остального хватит простого Adjacency List.

Как угробить очередной проект? Начните с реализации nested sets.
Может быть вы просто не умеете их готовить? ;-)
у меня полноценное управление Nested Sets'ом — на php 300 строчек. один раз написал, а потом используй, и длинна запросов у тебя уменьшится в пару раз точно и удобно и понятно и никаких геморов
Да, если все-таки хочется выстрелить себе в ногу, то можно взять хотя бы алгоритм path enumeration. Все современные бд умеют оптимизировать запросы like.

Для postgres есть даже модуль специальный: www.sai.msu.su/~megera/postgres/gist/ltree/
Да даже like не нужен, если путь по колонкам распихать
«Достойное» решение.
Без комментариев.
Если не согласны, то уж постарайтесь аргументировать, а не только делать вид всезнающего.

Небольшая избыточность при распахивании пути по колонкам выдаёт большую скорость, так как поиск уже осуществляется по индексированным целочисленным полям, плюс ко всему появляются возможности работы с иерархией как в алгоритме NS. На практике глубина иерархии больше 10 редкость, вы либо создаёте 10 колонок, либо тратите процессорное время с вашим алгоритмом для NS. Всё же следует для каждой задачи применять соответствующее решение. За статью про NS спасибо, но его уже со всех сторон изжевали, хотелось бы увидеть что-то новое.
Тут даже дело не только в cpu, а в том, что запросы с case/if/триггеры и прочими сложными вещами напрочь сносят возможные выигрыши от того, что все дерево выбирается сразу. На небольшом кол-ве уровней, это даже и медленнее, наверное.

А если добавить к Adjacency List кэширование, тогда у меня вообще ничего до базы не долетит.

Что в итоге?

Сложный алгоритм, непрозрачный код, ад в поддержке.

Я например, видел стопицот реализаций nested sets, но ни разу не видел unit tests на эти реализации.
p.s. Когда в пример приводят то, что многие операции в nested sets над деревом делаяются как o(1), то забывают что это важно только тогда, когда константные множители перестают играть роль.
Если вы не понимаете алгоритма, не используйте, я же вам его не навязываю.

> что запросы с case/if/триггеры и прочими сложными вещами напрочь сносят возможные выигрыши
Вот тут поподробней пожалуйста. Что сносит, в каких случаях и почему?
Я писал реализацию этого дерева еще пять лет назад, в рамках дипломной работы в институте. И алгоритм я вспомню, если нужно, но я писал не об этом совершенно.
А о чем?
Я провожу сравнения?
Я проповедую новую религию?
Нет, я предлагаю готовую реализацию, для тех, кто использует данный алгоритм.
Вы то, что тут делаете?
Ок. Хватит либеральничать :-) Ваш код никуда не годится из-за сложности поддержки, разработки и тестирования.
Сложность поддержки? Хм… если вы не будете менять поля используемые для Nested Sets, то вообще-то эти триггеры изменять не нужно.
Сложность разработки? Какой разработки?
Сложность тестирования? — Расхожее убеждение.

Вообще, если я использую в своих проектах этот алгоритм, то как минимум я знаю как он работает, если вы пять лет назад писали диплом на эту тему и не используете этот алгоритм в практике и не собираетесь, то вам этот код не годится. И что с того?
У меня складывается чувство, что я своей статьей чем-то вас обидел, подорвал моральные устои.
Найдите пожалуйста, где я сказал, что Adjacency List — это говно, и не надо его никогда использовать, что LTree говно, или другие решения.
Единственно, на что я посетовал, так это на то что в MySQl реализация триггеров — говно, а MERGE иногда работает, мягко скажем, неадекватно.
Есть алгоритм Nested Sets, вот вам его реализация на уровне триггеров.
Кому надо — используйте, кому не надо, чего рассказывать о том, что это вам не понятно сложно и вообще говно.
А не провожу никаких сравнений, а вам лишь бы хуем померяться.
Диалог совершенно неконструктивен.
Судя по тону, это я вас задел, а не наоборот :-) Я просто раскритиковал ваш код не с точки зрения самого кода, а с точки зрения его применимости и целеообразности вообще. Извините, что не приклонили колен перед великим изобретателем священного велосипеда! ^-)
Возможно и задели и не потому, что колен не преклонили.
А потому, что из-за того, что вы не понимаете алгоритма и никогда его не применяли, вы заранее утверждаете что это говно.
Во-первых, применял. Потому что как в любом приличном институте диплом делается на реальную работу и у меня даже был акт внедрения. Использование же nested sets там было оправдано, потому что там было довольно большое дерево(не редко, более 10 уровней).

И тогда я не понимал, на самом деле того, о чем сейчас пишу, критикуя ваш подход. Теперь понимаю.

Во-вторых, по коду.

Вот вы можете если не написать, то хотя бы сформулировать набор критериев, который является достаточным для написания unit-test-ов, которое покроет ваше api?
(вопрос скорее риторический, так как unit test-ов на nested sets я не видел).

Кстати, а на чем их писать? :-)

global lock — отлично!

myisam only — да еще при такой сложной структуре, это crash и вы даже руками уже ничего не восстановите.
> так как unit test-ов на nested sets я не видел

— Ты видишь в поле суслика?
— Нет.
— Но тем не менее он там есть.

doc.prototypes.ru/database/nestedsets/theory/rules/
Редкость не редкость, но когда у тебя 10 таких полей, и вдруг понадобилось еще 5, а в таблице уже более миллиона записей, и останавливать проект нельзя.
Как показывает практика, заведомое ограничение рано или поздно приводит к тому, что эти ограничения начинают существенно мешать.
Понадобится — добавьте, для этого только ALTER сделать, а весь миллион записей не нужно инициализировать, установка значений только у добавляемых узлов будет происходить точно также, если бы добавление колонок не потребовалось.

Да и ещё раз говорю, для каждой задачи свой алгоритм и не надо делать из NS универсальное решение (судя по комментам) — он хорош только, когда требуется работать с очень глубокой иерархией и если её изменение — редкость. Но так получается, что веб движется в сторону абсолютной динамичности, данные постоянно обновляются, поэтому такое внимание к алгоритмам изменяющие данные. Как раз для этого и оказалось выгодней MP алгоритм реализовать с небольшой избыточностью, чтоб и изменение иерархии происходило быстро и поиск/чтение тоже.
Читаем статью еще раз. Вникаем в суть.
Я не предлагаю замены, я предлагаю расширение Nested Sets, что бы его можно было использовать как и Adjacency List.
Вот ключевой момент всей дискусии. Никогда еще абстракция не добавляла надежности и устойчивости. Все абстракции «текут». Поэтому Nested Sets не будет обладать свойстами простоты и устойчивости Adjacency List. Теперь подумайте про myisam и «протечку» вашей абстракции, например.
Ну а что не так? Вам (да и мне) очень нравится как удобно в NS выборки делать и вы того же хотите добиться в управлении, так ведь? Вы скрыли логику в триггерах, но забыли главное — минимизировать нагрузку. Предложенный вами вариант не устраняет главного минуса NS.

> Я не предлагаю замены

А для чего статья? Кому она будет полезна, если этим не заменить другие алгоритмы? Не поленились бы хотябы написать, где это творение лучше всего использовать и привели бы сравнение с NS без триггеров.

Судя по всему вас в обще не интерисуют другие подходы. Как ещё объяснить резкую критику и сплошное минусование?
а в postgres есть массивы))
да там и добрый PL/Python есть… )
Судя по предыдущему комментарию, ожидаю очередной «перл» автора применимо к массивам в PostgreSQL.
А что используете вы, товарищ? Рекурсивные деревья?
PostgreSQL — тут не при чем, статья по нему по соседству.
ltree — не самое лучшее решение, особенно в части переноса веток, и подсчета.
Если речь идет о базе, то использую Adjacency List.
не совсем понял зачем поле tree и как с ним работать.
Поле tree нужно что бы можно было работать с несколькими деревьями в одной таблице.
Например есть таблица комментариев древовидных, но объектов комментирования много, соответсвенно для каждого объекта свое дерево комментариев.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории