Pull to refresh

Comments 19

UFO just landed and posted this here
Спасибо за замечания, исправил.
Не поверю, что чтение всего дерева в модели Mptt будет медленнее, чем Raw. В django-mptt при выгрузке всего дерева данные будут упорядочены, т.е. будет применяться сортировка.

У вас в Raw выгрузка дерева упорядочено или либо произвольное?
Исходники все в открытом доступе, если укажите в них на ошибку буду только рад. Для получения всего дерева я использую стандартный запрос Django:
model.objects.all()
во всех случаях.
В случае с MPTT дерево будет отсортировано! А в Raw нет! Если тестируете выгрузку всего дерева, то уж отсортируйте его. А иначе какой смысл этой выгрузки?

Если постотреть запросы которые идут в базе, то сортировки там нет, или вы имеете ввиду, что mptt сортирует данные при вставке?

django-mptt добавляет сортировку по двуь полям ".order_by('tree_id', 'lft')". А если вы тестируете выборку полного дерева без упорядочивание, то какой смысл в таком тесте?

def get_queryset(self, *args, **kwargs):
        """
        Ensures that this manager always returns nodes in tree order.
        """
        return super(TreeManager, self).get_queryset(
            *args, **kwargs
        ).order_by(
            self.tree_id_attr, self.left_attr
        )

Спасибо, за то что нашли неточность я перепроверю результат с учетом этого, просто странно что профайлер запросов Джанго не указал сортировку в sql запросе.

Я обновил диаграмму по считыванию дерева, добавлением сортировки ко всем запросам, но Raw все равно оказалась быстрее
Интересно, как вы сортируете в SQL выборку всего дерева в Raw?

И что в итоге вы получите? Набор строк отсортированных по parent_id? Это никак не дерево.

Я был бы вам очень признателен, если бы вы показали какой запрос надо выполнить для Raw дерева. И я бы провел замеры на нем.

Да я не уверен что можно построить полное дерево на одном SQL для формата Raw.

UFO just landed and posted this here
Согласен с MikeVL: для хоть какого-то приближения к реальным юзкейсам нужно при чтении всего дерева использовать «одинаковые» сортировки для всех 3х вариантов, а сейчас у вас:
1. для mptt и ltree сортировки вроде бы похожие и в основном идут «в глубину»
2. для raw у вас порядок будет совсем другой: сначала верхние узлы все деревьев, а потом вообще бардак – если при «упорядоченном» создании еще можно описать в каком порядке это всё идёт, то после того как вы поперемещаете деревья между родителям – начнётся полный бардак

Думаю вам нужно подумать над тем, чтобы для Raw сделать сортировку хотя бы похожей на порядок в mptt и ltree. Например получить все узлы без родителей, а потом для них вызывать get_descendants, но этоу уже явно не один запрос. Но и в этом случае ничто не гарантирует, что для Raw модели сохранится какой-либо адекватный порядок

И еще замечания:
1. в реальных ситуациях, когда данных много — вы не будете использовать list(QS), т.к. при таком подходе вы рискуете бесполезно использовать всю доступную память. Скорее в таких случаях вы бутете использовать iterator, или будете считывать небольшими порциями. (http://blog.etianen.com/blog/2013/06/08/django-querysets/). Мне кажется для чтения всего дерева правильнее было бы использовать подобный подход. А для отдельных узлов – вариант с list(QS) – ок
2. Методы которыми вы выбираете случайный узел каждый раз считывают всю таблицу – мне кажется это будет как-то влиять на поведение постгреса, но не уверен
3. в методе move_node_time, конечную точку вы выбираете случайно, без каких-либо проверок. Из-за этого вполне возможна ситуация, когда вы будете перемещать узел к одному из своих потомков – не особо понимаю как текущая логика Ltree.move_to справится с этим
4. Мне кажется, что после «перемешиваний», с помощью перемещений, после вставок узлов в случайные места ситуация может поменяться. И при этом, как по мне, такой набор данных будет ближе к «настоящим», но это уже спорный вопрос
Возможно вы не наследовали модель от класса MPTTModel, и поэтому не будет сортировки.
Но а если дерево не упорядочено, то зачем делать тест полной выгрузки? Ведь если этого не делать то скорость выгрузки будет примерно скорости выгрузки из БД. Да и что потом делать с этими данными?
Я работаю с .NET и SQL Server, и никогда не сталкивался ни с Python, ни с PostgreSQL, ни с Django. Однако мне крайне странно видеть подобные результаты замера производительности. Ведь вся суть моделей Nested Sets и Materialized Path в том, что они придуманы именно для ускорения чтения (выборка дерева/поддерева, определение количества узлов в поддереве, обход в ширину/глубину), жертвуя скоростью записи/модификации (удаление/добавление узлов/поддеревьев, перемещение узлов/поддеревьев). Будь в общем такие результаты по скорости, и модели Nested Sets и Materialized Path никогда бы не возникли.
А какую модель используете вы?

На самом деле, модель определяется кейсами. У каждой есть свои преимущества и недостатки. Nested sets — практически лучший алгоритм по части выборки (большинство типовых операций на дереве предельно просты), упорядочивание узлов «из коробки», но модификация дерева нетривиальна (поэтому часто используются gaps-модификацию). Adjacency lists — наиболее гибкий и сбалансированный, когда предполагается много операций на дереве, а основная таблица достаточно «широкая» (но только не его рудиментарный вид id+parent, а классический adjacency list в отдельной таблице, особенно хорошо для баз с поддержкой кластерных индексов). Materialized paths — самый убогий по всем показателям. Binary-модификация ещё куда не шло, но типовая строковая реализация… Есть ещё метод nested intervals. Решает те же проблемы, что и nested sets+gaps, но только без гвоздей.
Sign up to leave a comment.

Articles

Change theme settings