[PostgreSQL, Java, Тестирование веб-сервисов] История о PostgreSQL 13, Testcontainers и багах

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
29-Мар-2021 23:31

Привет Хабр!Несмотря на то, что на текущем месте работы взаимодействовать с PostgreSQL приходится значительно меньше, я продолжаю поддерживать свою библиотеку pg-index-health. Недавно я зарелизил версию 0.3.1, ключевой особенностью которой стала поддержка PostgreSQL 13.Эта история началась достаточно давно, ещё в октябре 2020. В процессе мне пришлось отказаться от embedded версии СУБД в тестах, перейти на Testcontainers, столкнуться с ошибкой в PG13 и даже немного пообщаться в переписке с одним из разработчиков Постгреса... Но обо всем по порядку.
Изначально для тестирования библиотеки я использовал embedded PostgreSQL. Я уже рассказывал об этом ранее. В целом это был неплохой вариант, но он завязан на чужие бинарники и их релизный цикл. Артефакта с 13-й версией долгое время не было (зарелизили только 13 ноября, спустя полтора месяца с момента начала моих экспериментов). Очевидно, что дальше жить с таким вариантом было крайне неудобно.Альтернативный подход тоже был известен – Testcontainers (спасибо Николаю Кондратьеву за всю подготовительную работу), но мне до последнего момента не хотелось на него переходить. Дело в том, что Testcontainers — это дополнительный достаточно толстый слой между приложением и базой, запускаемой в Docker-контейнере. На MacOS и Windows такое решение время от времени ломается. И я столкнулся с этим. Дважды. Сначала на MacOS, затем на Windows.Но что более печально, в Github Actions тесты с использованием Testcontainers можно запускать только на Ubuntu. По крайней мере у меня не получилось сделать это для Windows и MacOS. Если вы знаете, как настроить такую связку, буду премного благодарен за совет.В какой-то момент времени все тесты в моём проекте оказались переведены на Testcontainers и успешно проходили на 11-й и 12-й версиях. Затем я переключил проект на ванильный образ с 13.0... И тут меня ждал облом... Тесты на оценку bloat'а индексов упали. В отдельной ветке я подготовил проект для демонстрации этой ошибки.
Ошибки в тестах на PostgreSQL 13.0Первичный анализ ничего не дал. Никаких принципиальных изменений, которые бы ломали обратную совместимость между 12-й и 13-й версиями не было. Углублённое чтение release notes познакомило меня со сжатием дубликатов в b-tree индексах в новой версии - фичей, которую я ранее как-то совсем упустил (да, так тоже бывает).Возможно, эти доработки и стали причиной изменившегося поведения (а может и нет - на детальное изучение кодовой базы PostgreSQL у меня не было времени и сил). Но вот "баг это или фича" и как теперь правильно оценивать bloat индексов, я не понимал. В открытых источниках ничего полезного найти не удалось.И тогда я решил написать одному из соавторов доработок по сжатию дубликатов в b-tree индексах - Анастасии Лубенниковой. И… нет, здесь happy end'а не случилось: у Анастасии не было для меня готового решения, а потом навалилась работа, и на долгих два месяца я забросил проект...Вернуться к PG 13 удалось только в начале января 2021. И я решил попробовать недавно вышедшее минорное обновление 13.1. Представьте себе моё удивление и радость, когда на этой версии все тесты прошли. На 13.1 оценка bloat'а индексов снова стала работать корректно!Мораль этой истории проста и банальна: не стоит тащить новую версию любимой СУБД сразу в production. Ошибки бывают везде. Главное, чтобы они оперативно исправлялись. Ну а лично для меня приятным открытием стало то, что моё детище можно использовать как инструмент для acceptance testing (вернее, как его небольшую часть).А что там со сжатием дубликатов в b-tree, спросите вы? Может быть, оно способно полностью решить проблему с null value в индексах?.. Увы, нет.Сжатие дубликатов работает хорошо, даже замечательно. Вы можете проверить это самостоятельно. По ссылке подготовлен скрипт для инициализации и наполнения небольшой тестовой БД и команды для запуска двух разных версий СУБД в контейнере.Init-db скрипт
create table if not exists test
(
  id bigserial primary key,
  fld varchar(255),
  mark varchar(255),
  nil varchar(255)
);
insert into test
select data.id, case when data.id % 2 = 0 then now()::text else null end, case when data.id % 2 = 0 then 'test_string'::text else null end, null
from generate_series(1, 100000) as data(id);
create index if not exists i_test_fld_with_nulls on test (fld);
create index if not exists i_test_fld_without_nulls on test (fld) where fld is not null;
create index if not exists i_test_mark_with_nulls on test (mark);
create index if not exists i_test_mark_without_nulls on test (mark) where mark is not null;
create index if not exists i_test_nil_with_nulls on test (nil);
create index if not exists i_test_nil_without_nulls on test (nil) where nil is not null;
Команды для запуска в Docker
docker run --name postgres-13 -e POSTGRES_USER=testuser -e POSTGRES_PASSWORD=testpwd -e POSTGRES_DB=testdb -d -p 5432:5432 -v /absolute/path/to/initdb.sql:/docker-entrypoint-initdb.d/initdb.sql postgres:13.2
docker run --name postgres-12 -e POSTGRES_USER=testuser -e POSTGRES_PASSWORD=testpwd -e POSTGRES_DB=testdb -d -p 6432:5432 -v /absolute/path/to/initdb.sql:/docker-entrypoint-initdb.d/initdb.sql postgres:12.6
psql -U testuser -d testdb
SQL запрос для оценки размера индексов
select
  x.indrelid::regclass as table_name,
  x.indexrelid::regclass as index_name,
  pg_size_pretty(pg_relation_size(x.indexrelid)) as index_size
from pg_index x
join pg_stat_all_indexes psai on x.indexrelid = psai.indexrelid and psai.schemaname = 'public'
order by 1,2;
На выходе получим следующее:Результаты в текстовом видеPostgreSQL 12table_nameindex_nameindex_sizetesttest_pkey2208 kBtesti_test_fld_with_nulls3552 kBtesti_test_fld_without_nulls2456 kBtesti_test_mark_with_nulls2664 kBtesti_test_mark_without_nulls1568 kBtesti_test_nil_with_nulls2224 kBtesti_test_nil_without_nulls8192 bytesPostgreSQL 13table_nameindex_nameindex_sizetesttest_pkey2208 kBtesti_test_fld_with_nulls704 kBtesti_test_fld_without_nulls368 kBtesti_test_mark_with_nulls696 kBtesti_test_mark_without_nulls360 kBtesti_test_nil_with_nulls696 kBtesti_test_nil_without_nulls8192 bytesОбратите внимание, что размер индекса по первичному ключу, где все значения уникальны, не изменился.
Демонстрация сжатия дубликатовКак видите, выбрасывать null value из индекса целиком по-прежнему крайне выгодно, и этой диагностикой не стоит пренебрегать.Ну и напоследок. Embedded PG уходит в прошлое. Сейчас стоит отдавать предпочтение более современным и совершенным решениям наподобие Testcontainers.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_postgresql, #_java, #_testirovanie_vebservisov (Тестирование веб-сервисов), #_testcontainers, #_docker, #_postgresql, #_bloat, #_embedded_database, #_postgresql, #_java, #_testirovanie_vebservisov (
Тестирование веб-сервисов
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 10-Май 23:44
Часовой пояс: UTC + 5