demiurg ([info]demiurg) wrote,

SQL Trees (finished)

ладно, кажется мои "страсти по деревьям" подходят к завершению.
с механизмом я вроде бы определился, и окончательный выбор меня на самом деле немало удивил.
попробую обобщить здесь накопившуюся инфу о проведённых тестах.

чтоб не было потом лишнего пиздежа:
<disclaimer>
все нижеприведённые тесты некорректны априори!
сравнивались разные механизмы на двух совершенно разных СУБД, которые несравнимы.
единственное, что совпадало -- набор данных и структура дерева.
так или иначе, тесты я делал для себя, нужную мне информацию я получил, а всё остальное -- фпесду и ниибёт.
если появятся злоебучие крохоборы и борцы за Вселенскую Правду™, буду говорить лишь: "OMG STFU, don't bitch and get a life, dork!"
</disclaimer>

целью данных тестов было найти подходящий механизм хранения и обработки информации, структурированной в виде дерева, в СУБД PostgreSQL. механизм должен работать приемлемо быстро (кто как хочет, так и интерпретирует это определение) на деревьях в несколько тысяч нод, а также должен быть достаточно удобным на момент изменения содержимого дерева.

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


INSERT PATH
DESCENDANTS DELETE
вот так расположены графики следующих тестов:


INSERT - вставить необходимое кол-во нод в дерево.
набор данных и структура генерируются случайным образом однажды в самом начале тестов. поле "полезной нагрузки" в отдельной таблице лишь одно и содержит текст "node<N>", где <N> -- порядковый номер ноды.

PATH - для каждой ноды дерева получить её "путь" до корня дерева.

DESCENDANTS - для каждой ноды первого уровня получить всех её потомков.

DELETE - последовательно удалять каждую ноду первого уровня вместе со всеми её потомками.

вот теперь -- самое вкусное: описания графиков различных механизмов. хотя, описанием это назвать будет трудно, поэтому наверное лучше таки использовать термин обоснование.
гы, будет смешно, если потом окажется, что в тестах были грубые ошибки, и придётся точно так же всё обосновывать на противоположное. =)


ADJ-M - Adjacency List (MySQL)
несомненно, самый быстрый механизм.

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

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

SELECT nod_id FROM tree WHERE nod_id = ?nod_parent


и тем не менее, разница по PATH с другими механизмами на MySQL исчезающе мала!
всё это потому, что MySQL прямо таки резок как понос на простейших выборках по PRIMARY KEY и сделает на них любую другую "взрослую" СУБД.

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

на DELETE все остальные немножко обосрались по сравнению с ADJ-M, даже несмотря на то, что удаление шло в две стадии -- точно так же, как и выборка в DESCENDANTS -- сначала получить список нод, а потом уже их удалить.


NST-M - Nested Sets (MySQL)
очень хороший механизм! прямо таки самый-самый, если не брать во внимание жутчайшие тормоза на операции INSERT, где время работы растёт экспоненциально.

INSERT: пиздец-какие-тормоза! ноу комментс.
PATH: супер быстро. быстрее работает только RAL-M, потому что там запросы проще.
DESCENDANTS: круче нас тока йайца! выборка по уникальному индексу -- что может быть быстрее.
DELETE: то же, что и в DESCENDANTS -- очень даже хорошо


RAL-M - Redundant Adjacency List (MySQL)
механизм такой же, как и ADJ-M, только в таблице со структурой дерева храним ссылки не только на прямого потомка ноды, но и на всех её потомков.

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


RAL-P - Redundant Adjacency List (PgSQL)
ADJ-P - Adjacecncy List (PgSQL)
да-да, я там наебался маленько в агенде к графикам. то, что обозначено RAL-P следует читать как ADJ-P (потом может быть поменяю, сейчас не могу). почему я отказался от RAL-P я уже пояснил в предыдущем параграфе.

итак, переходим на другую платформу -- PostgreSQL, для которой всё и делается.
теперь в БД я усиленно использую хранимые процедуры и триггеры, ессно постоянно думая о скорости работы, но и давая себе отчёт в том, что все эти фишки так или иначе будут тормознее, чем голый король MySQL.
важно: дефолтный конфиг PostgreSQL я поменял, выдав ему то ли 64М, то ли 128М памяти для работы. то, что ему даётся по умолчанию -- просто смешно.

ADJ-P показал себя на самом деле просто суперски.

INSERT: линейный рост и скорость сравнима с ADJ-M, хотя на каждое добавление ноды идёт один лишний SELECT (получить кол-во существующих детей у родителя) и UPDATE (инкремент счётчика детей для родителя). это делается потому, что SELECT COUNT(*) в PostgreSQL сканирует всю таблицу (сравнить с MySQL, где эти данные берутся напрямую из дескриптора таблицы), поэтому получается дешевле поддерживать этот счётчик во время работы, чем пересчитывать его каждый раз по мере надобности.

PATH: да, пришлось реализовать рекурсию на процедуре, и выборка пути теперь производится красиво:

SELECT nod_id FROM path_of(?nod_parent)


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

DESCENDANTS: тормоза-тормоза! но зато хоть рост практически линейный, да и выборка идёт с помощью рекурсии в хранимой процедуре, как это сделано в PATH, что очень и очень удобно для клиентского кода.

DELETE: в клиентском коде опять сплошные удобства -- удаляем только одну запись, а об остальном позаботится FOREIGN KEY. небыстро, но всё ж лучше, чем...


INT-P Nested Intervals
да, у меня получилось таки имплементировать Вложенные Интервалы. ну и поеботень же!
теория красива донельзя: смесь Nested Sets и Redundant Adjacency List, всё хранится в двух целых числах.
проблемы вылазят лишь на момент жёсткого использования механизма.

прежде всего, ограничение на кол-во нод в дереве. числа растут неприемлемо быстро, и обычного INT'а начинает нехватать, а переход на BIGINT, боюсь, ещё более затормозит, да и всё равно проблемы это не решит.

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

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



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

  • Post a new comment

    Error

    Comments allowed for friends only

    Anonymous comments are disabled in this journal

    Your reply will be screened

    Your IP address will be recorded 

  • 25 comments

[info]nikanorov

November 22 2004, 01:41:20 UTC 7 years ago

А чего PostgreSQL так хорош?

[info]demiurg

November 22 2004, 01:43:35 UTC 7 years ago

мне понра.
хранимые процедуры, триггеры, FOREIGN KEYS...
причём, PgSQL уже находится в своей 8-ой версии и все эти фишки там существуют давно, а значит всё уже хорошо отлажено и just works.

[info]bopm

November 22 2004, 01:54:15 UTC 7 years ago

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

[info]nikanorov

November 22 2004, 02:01:14 UTC 7 years ago

Ага и под mono вроде как? Кстати, у тебя wiki вроде было, дай глянуть, а? =)

[info]bopm

November 22 2004, 02:04:50 UTC 7 years ago

bopm.maloletka.ru

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

[info]nikanorov

November 22 2004, 02:07:30 UTC 7 years ago

Re: bopm.maloletka.ru

Вроде был же порт под mono, где-то на dev.udaff.com?

[info]bopm

November 22 2004, 02:09:19 UTC 7 years ago

Re: bopm.maloletka.ru

Тебе показалось. В текущий момент есть только планы по intercommunion.info.

[info]nikanorov

November 22 2004, 02:13:11 UTC 7 years ago

Re: bopm.maloletka.ru

А, вот почему мне так показалось, узрел в твоём wiki (http://bopm.maloletka.ru/GoMono?v=18ic):
Что достигнуто на данный момент:

1. на http://devel.udaff.com собран mono (из cvs).
2. собран и запущен модуль для апача.

[info]bopm

November 22 2004, 02:14:32 UTC 7 years ago

Re: bopm.maloletka.ru

Полная ссылка несколько другая =) Моя ошибка. Да и потом, с тех пор многое изменилось.

[info]nikanorov

November 22 2004, 02:18:37 UTC 7 years ago

Re: bopm.maloletka.ru

intercommunion.info -- что это? =)

[info]bopm

November 22 2004, 02:19:53 UTC 7 years ago

Re: bopm.maloletka.ru

Увидишь. Пока оно только хидеры отдает =)

[info]nikanorov

November 22 2004, 02:25:48 UTC 7 years ago

Re: bopm.maloletka.ru

Ок. Запиши меня в intercommunion.info Development Test Command. =)

Anonymous

April 28 2007, 14:44:34 UTC 5 years ago

Re: bopm.maloletka.ru

интересно

[info]bopm

November 22 2004, 02:10:26 UTC 7 years ago

Какой такой язык у тебя в офисе?

[info]demiurg

November 22 2004, 02:11:53 UTC 7 years ago

в смысле?

[info]bopm

November 22 2004, 02:13:47 UTC 7 years ago

Ага, присмотрелся. Не у тебя. А то я прямо испугался =)

[info]demiurg

November 22 2004, 02:14:56 UTC 7 years ago

а! на картинках что ли?
это у меня. испанский =)
но эт только в офисе. дома -- английский.

Anonymous

November 25 2004, 01:12:52 UTC 7 years ago

"выбрал ADJ-P" :-)
вопрос главный что в дереве
а ты об этом умолчал скромно :-)

вставки-удаления, это все не имеет смысла само по себе
а что если мы вставляем раз в год?
не удалем вообще?
классические проблемы типа тех что описывает целко -- суммы по чайлдам
или какие другие
это должно выбор определять :-)

[info]demiurg

November 25 2004, 01:18:42 UTC 7 years ago

в данном случае в дереве -- только тестовые данные: одна строка "node", где -- порядковый номер ноды.

"если мы вставляем раз в год" не канает. вставки будут довольно часто случаться, что сразу же перечёркивает Вложенные Множества на объёмах, больших нескольких тысяч нод (это очень мало).

"не удаляем вообще" -- оно конечно правильно с точки зрения теории баз данных, но мы живём в реальном мире, и всякую хрень приходится за собой подчищать периодически =)

в данном случае я выбираю механизм по производительности и удобству работы с ним из клиентского кода на РНР. ADJ-P мне показался (и до сих пор кажется) оптимальным.

Anonymous

November 25 2004, 01:23:49 UTC 7 years ago

по удобству клиентского кода решение однозначно правильное, думаю понятно почему :-)

но таки ты не сказал *что* это будет :-)
ибо возможнны варианты
например мы использовали еще всякие комбинированные схемы
типа nested sets к которым листья крепятся как AL

btw ты не хочешь выложить серверный код?
sp etc
может соптимизируем чего

[info]demiurg

November 25 2004, 01:33:27 UTC 7 years ago

будет ORM, т.е. относительно много нод на нескольких деревьях разного размера, и всё будет достаточно "живое", т.е. меняться с хорошей периодичностью.

статистику посещений в риал-тайме туда ессно никто пихать не будет, также как и форумы на сотни тыщ постов, но какой-нибудь "сайтик" на несколько тысяч страниц/документов/товаров должно будет держать не напрягаясь, иначе жоппа. =)

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

Anonymous

November 25 2004, 01:32:35 UTC 7 years ago

да вдогонку

> линейный рост и скорость сравнима с ADJ-M, хотя на каждое добавление ноды идёт один лишний SELECT (получить кол-во существующих детей у родителя)

как делал это? :-)

[info]demiurg

November 25 2004, 01:34:29 UTC 7 years ago

SELECT nod_count FROM nodes ORDER BY nod_count DESC LIMIT 1
под Постгресом оно так индексы юзает в отличие от SELECT COUNT(*) ...

[info]sundrop

December 2 2004, 07:19:43 UTC 7 years ago

Вопрос!
Где можно почитать об алогритмах?

[info]demiurg

December 2 2004, 07:31:19 UTC 7 years ago

в интернете. гугль тебе в помочь.
все названия даны, разве что только обозначение RAL -- моя собственная выдумка, но там всё и так ясно и понятно.
Create an Account
Forgot your login or password?
Facebook Twitter More login options
English • Español • Deutsch • Русский…