Большой Воронежский Форум
Веб-программирование>Иерархический запрос в MySQL
Eвгений 15:36 23.09.2014
Советик нужен небольшой. веб-программирование я подзабросил этак лет 7 назад, многое подзабыл...
А тут потребовалось написать небольшой каталог на MySQL.
Дерево организовано просто - есть таблица catalog с полями id, parent_id и caption. Что для чего, думаю объяснять не нужно.
Длина ветвей различна, но не больше 5-ти.
Конченый (бездетный) элемент каталога связан с записями другой структуры в другой таблице (то есть в этой таблице записи имеют parent_id, равный id одного из "бездетных" элементов каталога)
Пару дней я вспоминал php и mysql, написал скриптик, вроде все хорошо, но вот каприз меня взял - хочу после названия элемента каталога писать сколько у него всего потомков, и делать случайную выборку из потомков, принадлежащих какому-то определенному родителю.

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

В общем, пока я ждал ответов на свои вопросы и тихо окуевал с nested set (сложно после долгого перерыва в такую жуть вникнуть), чисто из нетерпения и покалывания шила в одном месте, я набросал скрипт, который рекурсивно сканирует каталог, получает список id конечных элементов нужной ветви, а уже из этого списка клеит запрос для SQL в другую таблицу.
Работает правильно, надежно и без глюков.

Но меня кое что смущает.
В каталоге несколько сотен элементов, задача максимум - полное сканирование от корня до конечных ветвей, при вложенности, равной 5-ти, повлекло за собой 400 запросов. Сколько времени - я не мерял, но субъективно - мгновенно, несоизмеримо со временем загрузки страницы.
Далее, получив список из 400 с чем-то конечных элементов каталога скрипт сварганил такой запрос:
SELECT * FROM table2 WHERE parent_id IN ('1','2','3',.......'450')

Забил table2 мусором из 1500 записей и кинул вышеуказанный запрос. Его выполнение заняло 0.0042 сек.
В конечном проекте количество каталогов вряд ли превысит 500, а вот элементов будет около 100 000. То есть при наихудшем раскладе 0.42 сек на полный анализ.

У меня вопрос следующий - быстродействие то вроде бы удовлетворительное, но по сути, это же изврат...Хостер на меня не обидится? Вы бы стали оставлять так как есть? [Ответ]
silly 20:12 23.09.2014

Сообщение от Eвгений:
В конечном проекте количество каталогов вряд ли превысит 500, а вот элементов будет около 100 000.

Каталог или каталоги?

Сообщение от Eвгений:
Его выполнение заняло 0.0042 сек. ... То есть при наихудшем раскладе 0.42 сек на полный анализ.

Не думаю. Кэши, буферы и т. д. (Или это про id in (…) было?)

Сообщение от Eвгений:
Хостер на меня не обидится?

Э… выделенный сервер? (Можно не отвечать.)

Сообщение от Eвгений:
Вы бы стали оставлять так как есть?

Postgres наверно бы взял… [Ответ]
Eвгений 20:42 23.09.2014
silly,

Сообщение от :
100 000 чего?

Элементов во второй таблице. Которые принадлежат узлам дерева (каталога) в первой таблице.
Я к чему это написал - MySQL при запросе будет анализировать каждую из 100 тыс записей на предмет соответствия parent_id каждой записи одному из 400 идентификаторов. 1500 записей анализщируется за 0.0042 сек.

Сообщение от :
Э… выделенный сервер? (Можно не отвечать.)

Нет, какой-нибудь обычный бюджетный. Уж ответьте, я еще раз говорю - сильно отстал от жизни, да и тогда не приходилось работать с огромными базами. Если Вам что-то смешно, то мне нет, уж будьте добры, без иронии.

В смысл Nested Set въехал. По сути это та же рекурсия, мой скрипт проходит по дереву каталога тот же путь, что и leftkey и rightkey.
Только у моего скрипта это как-то само получается, а тут все разжевывать надо.
Пытаюсь понять, насколько MySQL будет быстрее с этим справляться. [Ответ]
Eвгений 20:48 23.09.2014
Хм... а ведь в Nested Sets это будет даже проще и точно быстрее. Нужно просто выбрать записи, где разница между leftkey и rightkey не больше единицы - это и будут концевые, "бездетные" узлы.
Но этой процедурой мы лишь избавляем MySQL от 400 запросов.
Но еще нужно выбрать в таблице №2 все элементы, принадлежащие одному из 400 идентификаторов, полученных в предыдущем запросе. [Ответ]
silly 20:57 23.09.2014

Сообщение от Eвгений:
Я к чему это написал - MySQL при запросе будет анализировать каждую из 100 тыс записей на предмет соответствия parent_id каждой записи одному из 400 идентификаторов. 1500 записей анализщируется за 0.0042 сек.

Просто индекс на parent_id поставь, в 100 раз медленней не будет.

Сообщение от Eвгений:
Нет, какой-нибудь обычный бюджетный. Уж ответьте, я еще раз говорю - сильно отстал от жизни, да и тогда не приходилось работать с огромными базами. Если Вам что-то смешно, то мне нет, уж будьте добры, без иронии.

Заметят — выгонят (без иронии).

Сообщение от Eвгений:
В смысл Nested Set въехал. По сути это та же рекурсия, мой скрипт проходит по дереву каталога тот же путь, что и leftkey и rightkey.
Только у моего скрипта это как-то само получается, а тут все разжевывать надо.
Пытаюсь понять, насколько MySQL будет быстрее с этим справляться.

Если в первой таблице всего 500 записей, то выбрать их все одним запросом, построить дерево в программе, сложить результат в кэш. [Ответ]
Вверх