Параллельные запросы для PostgreSQL были долгое время моей мечтой, над которыми я работал несколько лет. Их разработка их началась c PostgreSQL 9.4 релизном цикле, где я добавил динамические воркеры, работающие в фоне и динамическую shared memory, разработка которой продолжилась в PostgreSQL 9.5, где имела место идея в добавлении фундаментальной инфраструктуры для параллелизма которая сегодня была закоммиченна. Я хотел бы рассказать вам немного о сегодняшних коммитах и о работе, которая будет проделана дальше.
Но первое, что я хотел бы сделать это поблагодарить тех, кого я должен. Во первых Amit Kapila, который внес громадный вклад в завершение проекта. Мы вдвоем написали большое количество кода, который стал полноценной частью этого функционала. И часть этого кода прошла через множество коммитов в течение последних нескольких лет. Так же мы написали большое количество кода, который не вошел в коммиты. Во-вторых, я хочу сказать спасибо Noah Misch, который хорошо помогал мне на ранних стадиях в этом проекте, когда я боролся с проблемами в поисках пути их решения. В-третьих, я хотел бы сказать спасибо PostgreSQL комьюнити и отдельным людям, которые поддерживали review и тестовые патчи, предложенные усовершенствования и многим другим, кто нас поддерживал разными способами.
Так же важно сказать спасибо EnterpriseDB, в частности, ее руководству. Во первых, Tom Kincaid и Marc Linster. Без их поддержки было бы не возможно нам с Ammit's посветить много времени этому проекту, а так же без моей команды в EnterpriseDB, которые терпеливо прикрывали меня всякий раз, когда нужно было решать другие рабочие вопросы. Спасибо всем.
Теперь, время для demo:
rhaas=# \timing
Timing is on.
rhaas=# select * from pgbench_accounts where filler like '%a%';
aid | bid | abalance | filler
-----+-----+----------+--------
(0 rows)
Time: 743.061 ms
rhaas=# set max_parallel_degree = 4;
SET
Time: 0.270 ms
rhaas=# select * from pgbench_accounts where filler like '%a%';
aid | bid | abalance | filler
-----+-----+----------+--------
(0 rows)
Time: 213.412 ms
Вот как выглядит план:
rhaas=# explain (costs off) select * from pgbench_accounts where filler like '%a%';
QUERY PLAN
---------------------------------------------
Gather
Number of Workers: 4
-> Parallel Seq Scan on pgbench_accounts
Filter: (filler ~~ '%a%'::text)
(4 rows)
Накапливающий узел собирает все воркеры, и все воркеры запускаются в дополнительном плане параллельно. Потому что дополнительный план Parallel Seq Scan — обыкновенный Seq Scan. Воркеры координируются с друг другом так, что каждый блок в отношении сканируется только один раз. Каждый воркер может производить подмножество финальных result set, а собирающий узел собирает результаты со всех.
Одно достаточно больше ограничение текущей реализации является то, что мы генерируем сборщиков узлов на вершине Parallel Seq Scan узлов. Это означает, что эта функция в настоящее время не работает для иерархии наследования (с использованием разделенного партицирования таблиц), потому что её можно будет добавить между узлами. Так же не возможно протолкнуть join вниз в воркеры в настоящее время. Исполнитель инфраструктуры поддерживает запуск планов каждого типа, но текущий планировщик слишком глуп для поддержки этого. Я надеюсь исправить эту проблему до окончания релизного цикла 9.6. С учетом текущего положения вещей использование этой фичи будет давать преимущество там, где добавление индекса уже не помогает и добавление нескольких воркеров поможет увеличить скорость выполнения.
Так же мой опыт говорит, что добавления нескольких воркеров как правило помогает, и преимущество плохо масштабируются с большим количество воркеров. Так же необходимо более глубокое исследование, чтобы понять почему это происходит и как это улучшить… Как вы видите даже 5 воркеров могут повысить производительность совсем немного, но это не так важно как в предыдущем ограничении. Однако, я хотел бы совершенствовать их дальше, так как количество CPU растет все это время.
В завершении, я хотел бы отметить, что есть еще ряд определенных задач, которые должны быть закончены, прежде, чем я могу назвать эту функцию даже в базовой форме полностью законченной. Вероятно что еще остались ошибки. Тестирование очень высоко ценится. Пожалуйста, сообщите проблемы, которые вы найдете при тестировании на pgsql-hackers и postgresql.org. Спасибо.
Комментарии (11)
yusman
18.01.2016 15:33Спасибо!!! Очень нужная вещь. Открываются новые возможности для PostgreSQL в аналитических запросах.
wildraid
18.01.2016 20:56Очень люблю PostgreSQL, но, как мне кажется, зря он пошёл в этом направлении.
Существуют аналитические СУБД, которые изначально были построены с расчетом на параллельное выполнение запросов на множестве ядер или даже множестве серверов. Там всё заточено под это: и способ хранения, и компрессия, и протоколы, и планы выполнения.
А тут такой Постгрес выходит и говорит, что он теперь поддерживает 5% подобных функций, а через годик-другой будет поддерживать 20%. И то путём титанических усилий по переделке ядра, которое никогда не задумывалось для параллельного выполнения.
Ну и какой практический смысл в этом? Я бы лучше сконцентрировался на том, в чём PG по-настоящему силён, а аналитику оставил бы для специализированных продуктов.yusman
18.01.2016 21:59Зря вы так, популярные аналитические продукты Vertica, Gpreenplum, netezza, Postgres-XL и т.п. базируются на PG. Они то уж найдут этой фиче применения в будущем.
Ivan22
19.01.2016 14:58ну так они уже ушли далеко вперед. О чем и речь, в них уже все это есть. Паралельный и скан и сорт и поиск и группировка и джоины!!!
Т.е. в общем-то это либо PG будет у них заимствовать, либо будет просто их догонять.yusman
19.01.2016 15:27Да, но там эта задача решается запуском сразу нескольких инстансов postgresql на одной ноде. Например хотите что бы на каждом узле распараллеливание было равно 5 — запускается 5 postgresql серверов на ноде и каждый молотит свой кусок данных.
У такого подхода есть свои минусы, накладные расходы, нельзя «на лету» менять степень параллелизма.Ivan22
19.01.2016 17:27верно, но степень параллелизма и так уже достаточна. Пример — наша база, 24 физических сервера и на каждом 4 инстанса (+4 резервных) = 96 степень параллелизма. Это и так весьма немало. Уже сейчас узкое место — межсетевой обмен данными на нодах.
Ivan22
вопросы:
1. Если сейчас у нас стандартно есть один скан на сервере выполняется за время Х, при паралельном скане — он выполняется быстрее, но как я понимаю — уже при паралелизме в 5 прироста дальнейшего нет. Означает ли это, что если у нас есть 4-5 или больше одновременных запросов со сканами на сервере — то включение паралелизма не ускорит процесс?
2. Как на счет параллел сорт???
3. Как на счет параллел индекс скан?
4. При джоинах — есть ли выйгрышь, если джоийним с фулсканами??
itcoder
В теории, если у вас работает одновременно 5 запросов на сервере при включении например: set max_parallel_degree = 4; и при условии что у вас 4 ядра, ресурсы должны распределиться на 4 ядра и запросы должны выполняться быстрее.
Что касается сортировок агрегаций и index scan – то скорее всего разработчики будут над ними работать в будущем, но пока этого нет.
Ivan22
вообще я как-то смутно представляю себе связь скорости фулскана и количества ядер. У меня все в голове в диски упирается.