Сравнение производительности иерархических моделей Django и PostgreSQL
- вторник, 23 мая 2017 г. в 03:14:10
Добрый день, уважаемые читатели.
Сегодняшняя статья будет посвящена сравнению моделей работы с иерархическими данными в PostgreSQL, через Django приложение. В статья я специально не использую чистую реализацию в базе данных, т. к. меня интересует именно производительность в среде, приближенной к боевой.
Все тесты проводились на моих данных и результаты являются актуальными именно для этих данных, на ваших данных результат может отличаться от полученных в статье.
Для работы с такими структурами в PostgreSQL могут использоваться следующие модели:
Также подробней об реализации иерархических структур в реляционной БД можно почитать здесь.
Для их реализации в Django выбраны следующе инструменты:
Тестирование будет проводится на наборе данных из 150 тыс компаний. Время будет замеряться для
следующих запросов:
Временем выполнения запроса будет считаться среднее время выполнения 1000 запросов по каждому пункту, к случайно выбранному элементу дерева.
Для тестирования создано отдельное Django приложение. В нем создано по 3 модели, по одной на каждую схему хранения описанные выше. Это сделано для того, чтобы в любой момент можно было провести аналогичное тестирование на различных наборах данных.
В данном приложении реализовано две команды:
load_tree
— загружает данные для теста analize
— выполняет сбор и анализ данных исходя из заданного количества запросовДля запуска приложения и сбора статистики нужно выполнить последовательность команд:
python manage.py migrate
python manage.py load_tree <путь до файла с данными>
python manage.py load_tree analize <кол-во запросов для анализа>
Результаты команды analize
хранятся в папке report.
После выполнения указанных команд, для своих данных, я получил следующие резальтаты. Для того, чтобы названия моделей не вводили вас в заблуждение, ниже приведу соответствие моделей из теста и моделей хранения:
Как видно из диаграммы, худший результат тут показала модель Mptt, остальные две модели находятся приблизительно на одно уровне, хотя нативная модель Raw оказалась быстрее.
В данном тесте, в отличии от предыдущего пункта, модель Mptt сравнялась по скорости со стандартной реализацией, а вот Ltree напротив ухудшил свой результат. Надо отметить что в модели Raw для получения потомков используется рекурсивный запрос (WITH RECURSION), и, не смотря на это, он отработал быстрее всех.
При вставке узла опять отстала модель Ltree, но в данном случае это скорее всего связано с тем, что поле пути в котором хранится дерево состояло из id записей, поэтому мне пришлось делать 2 запроса (insert, а потом update поля path), что соответственно сказалось на производительности.
В премещении узла с поддеревом Mptt показал худший результат, это связано скорее всего с тем что при перемещении он должен пересчитать все поля у переносимых узлов, что является не быстрой операцией. Перемещение Raw является самой быстрой, т. к., по сути, это просто обновления одного поля. Ltree не на много отстал от лидера, так как он должен обновить пути у всех всех узлов переносимого поддерева.
Почтав сравенния реализации иерархических струтктур я ожидал, что лучший результат покажет реализация модели MP(Ltree), но, к моему удивлению, она показала лишь второй результат, уступив нативной реализации модели AM(Raw). Ну а реализации модели NS(Mptt) досталось 3-е место, так как в 2 тестах из 4 он проиграл с большим отрывом от конкурентов.
Сводная таблица с результатами:
model | insert_node | move_node | read_node | read_tree |
---|---|---|---|---|
Ltree | 0.001955 | 0.010375 | 0.008745 | 0.025522 |
Mptt | 0.001006 | 0.855293 | 0.00104 | 0.115597 |
Raw | 0.001002 | 0.001 | 0.001012 | 0.021957 |
Так же надо отметить, что результаты могут разнится для других наборов данных и поэтому перед принятием решения рекомендуется провести аналогичный тест для своих данных.
P.S. Это кросс-пост оригинальной статьи с моего блога