15 сентября в Авито прошёл митап, на котором мы говорили о масштабировании приложений на PostgreSQL. Сегодня я хочу поделиться материалами с него — видеозаписями, презентациями от докладчиков, показать фото. Также под катом публикую разбор вопросов викторины, которую мы проводили здесь, на Хабре, перед митапом. И рассказываю о своих впечатлениях от встречи.
Доклады
Распределенные транзакции и путешествия во времени. Стас Кельвич, Postgres Professional
Стас рассказал про распределенные транзакции и путешествия во времени.
Отзывы:
Стас со своей командой сделал прекрасную работу! Надеюсь их решение одобрит community и мы увидим это решение в новой версии Postgres.
Масштабирование приложения на PostgreSQL в Авито: tips and tricks. Константин Евтеев, Авито
Я выступил с докладом про масштабирование приложения на PostgreSQL в Авито и поделился нашими tips and tricks.
Отзывы:
Интересный подход: в котором Костантин очень увлекательно и доходчиво разьяснил с какими проблемами можно столкнуться при работе с данными в микросервисной архитектуре, а также предложил пути решения при масштабировании ИС. Saga запомнилась:)
Логическая репликация и уровни изоляции транзакций PostgreSQL. Михаил Тюрин
Михаил приготовил доклад о логической репликации и уровнях изоляции транзакций PostgreSQL.
Отзывы:
Михаил осветил тонкие моменты транзакций, которые далеко не сразу видны не только новичкам. Об этом нужно знать всем.
OZO — асинхронная типобезопасная header-only библиотека клиент PostgreSQL для C++17. Сергей Хандриков, Яндекс
Сергей рассказал слушателям о том, как устроена OZO, асинхронная типобезопасная header-only библиотека-клиент PostgreSQL для C++17 и пригласил контрибьютить в неё.
Отзывы:
Автору на мой вгляд удалось в сжатые сроки достаточно обзорно раскрыть проблемы в существующих библиотеках и пути решения в новых библиотеках C++. Поэтому рад буду, если данные библиотеки будут развиваться в opensource, тем более базовые вещи уже реализованы, что не может не радовать.
Ответы на вопросы викторины
Перед митапом мы предлагали вам ответить на вопросы по Postgres. Сегодня хочу показать правильные ответы. Они под спойлерами (на всякий случай).
Есть пустая таблица без записей users ("UserId" int, "balance" int). Что вернется в результате выполнения запроса?
with ins as (
insert into users
select
gs, gs * 10
from
generate_series(1, 4) gs
where
gs%2 = 0)
select * from users;
Ничего.
Что вернет запрос select * from users where UserId = 10;
при обращении к таблице users после выполнения предыдущего задания?
ERROR: column "userid" does not exist.
Определен Enum CREATE TYPE status AS ENUM ('wait', 'init', 'run', 'stop'); Какой командой можно удалить значение 'init'?
Стандартного способа удаления значения из enum нет.
Как можно получить список функций в PostgreSQL?
select * From pg_proc;
Что вернется в результате выполнения запроса?
select null = null, null is null, 1::smallint::boolean is true, null::bigint > 1
ERROR: cannot cast type smallint to boolean.
Junior-разработчику Васе поручили написать запрос, который выводит все записи из таблицы parent
, для которых нет записей в таблице child
.
Схема данных:
create table parent (parent_id serial primary key, payload text);
create table child (child_id serial primary key, parent_id integer unique references parent (parent_id));
Вася очень старался и не хотел ударить в грязь лицом, поэтому придумал восемь различных запросов для решения задачи:
-- 0
select
p.parent_id, p.payload
from
parent p
where
not exists(select from child c where c.parent_id = p.parent_id);
-- 1
select
p.parent_id, p.payload
from
parent p
where
not (array[p.parent_id] && array(select c.parent_id from child c));
-- 2
select
distinct p.parent_id, p.payload
from
parent p full join child c
on (c.parent_id = p.parent_id)
where
c.parent_id is null;
-- 3
select
p.parent_id, p.payload
from
parent p
where
p.parent_id not in (select c.parent_id from child c);
-- 4
select
p.parent_id, p.payload
from
parent p left join child c
on (c.parent_id = p.parent_id)
where
c.parent_id is null;
-- 5
with w_child_with_parents as (
select
c.parent_id,
( select count(*) from parent p where c.parent_id = p.parent_id) = 1 as parent_exists
from child c)
select
p.parent_id, p.payload
from
parent p
where
p.parent_id in (select pc.parent_id from w_child_with_parents pc where not pc.parent_exists);
-- 6
select
p.parent_id, p.payload
from
parent p full join child c
on (c.parent_id = p.parent_id)
group by
p.parent_id,
p.payload
having count(c) = 0;
-- 7
select
p.parent_id, p.payload
from
parent p
where
p.parent_id in ( select p2.parent_id from parent p2 except all select c2.parent_id from child c2);
Вася представил свои варианты вам, чтобы вы помогли выбрать ему лучший. Он утверждает, что все запросы работают одинаково: таблицы помещаются в память и разница в производительности не значительна (или даже незаметна). Однако, вы как более опытный разработчик заметили, что, возможно, не все запросы решают поставленную задачу. Перечислите запросы, которые не решают поставленную задачу (и объясните почему).
Поставленную задачу не решают запросы 2, 3 и 5 (в некоторых случаях так же запрос 1).
Тестовые данные:
«Некорректность» поведения проявляется, когда существуют записи в таблице child с parent_id is null.
insert into parent
(parent_id, payload)
values
(1, 'payload 1'),
(2, 'payload 2'),
(3, 'payload 3'),
(4, 'payload 4'),
(5, 'payload 5');
insert into child
(child_id, parent_id)
values
(1, 1),
(2, 3),
(3, null),
(5, 5);
На приведенных тестовых данных
- Запрос 1 в зависимости от того установлено ли расширение intarray может работать или не работать.
- Запрос 2 возвращает лишнюю строку (null, null).
- Запросы 3 и 5 возвращают пустой резалтсет.
Интерпретация результатов эксперимента
Запрос 1: в случае, если в базе данных установленно расширение intarray (https://www.postgresql.org/docs/current/static/intarray.html), запрос падает с ошибкой "ERROR: array must not contain nulls". Данное поведение связано с тем, что расширение переопределяет стандартные операторы и изменяет поведения для массивов, содержащих null-элементы.
Документация говорит следующее:
The operators &&, @> and <@ are equivalent to PostgreSQL's built-in operators of the same names, except that they work only on integer arrays that do not contain nulls, while the built-in operators work for any array type. This restriction makes them faster than the built-in operators in many cases.
Запрос 2: из-за full join в результате появляется лишняя строка (null, null).
Запрос 3: возвращает пустой резалтсет из-за того, что во множестве, формируемым подзапросом есть null-элементы.
Документация (https://www.postgresql.org/docs/current/static/functions-subquery.html#FUNCTIONS-SUBQUERY-NOTIN):
Note that if the left-hand expression yields null, or if there are no equal right-hand values and at least one right-hand row yields null, the result of the NOT IN construct will be null, not true. This is in accordance with SQL's normal rules for Boolean combinations of null values.
Запрос 5: возвращает пустой резалтсет потому, что в секции w_child_with_parents производится заход, с таблицы child и parent_id оказывается пустым или не отражается в секции вовсе.
На все вопросы викторины правильно ответили три участника. Одному мы вручили приз на митапе, ещё два комплекта сувениров отправились почтой.
Послесловие
На митап пришло более сотни человек. Очень приятно было встретить такую аудиторию. Согласно опросу, более 60% гостей митапа имеют опыт работы с базами данным более пяти лет. И очень приятно, когда доклады получают такую живую реакцию от слушателей:
В кулуарах встречи много говорили о том, что PostgreSQL становится всё более распространенным инструментом. Это действительно так. Пользуясь случаем, скажу, что мы в Авито планируем расширять команду DBA, и если вам интересны амбициозные задачи на большом проекте, посмотрите ваканисю на Моём Круге или напишите мне.
И в заключение хочу поблагодарить коллег из Яндекс, Postgres Professional и, конечно, Авито за замечательные доклады, которые мы услышали. Спасибо гостям, которые пришли к нам в этот субботний день и зрителям прямого эфира. И конечно, сообществу #RuPostgres за доверие.
Плейлист со всеми докладами здесь.
Фотоотчёты мы выложили на фейсбук и вконтакте.
До новых встреч!