Примеры реальных патчей в PostgreSQL: часть 3 из N

  • Tutorial

Сегодня я хотел бы вновь рассказать о некоторых патчах, принятых за последнее время в PostgreSQL (а также утилиту pg_filedump). Аналогичные статьи, опубликованные на Хабре ранее, набрали достаточно много плюсиков, что заставляет думать, что они представляют для кого-то интерес. Если вы пропустили предыдущие статьи, вот они — раз, два, три. Несмотря на то, что рассмотренные патчи были написаны мной, не стоит забывать о вкладе людей, которые их ревьювили и тестировали. Проделанная этими людьми работа зачастую оказывается больше и сложнее работы самого автора. Особо активное участие в разработке рассмотренных пачтей приняли Федор Сигаев, Robert Haas, Tom Lane, Дмитрий Иванов, Григорий Смолкин, Andres Freund, Анастасия Лубенникова и Tels.


11. pg_filedump: возвращение ненулевого кода возврата в случае ошибок


Напомню, что утилита pg_filedump предназначена для декодирования сегментов таблиц и вывода информации о заголовках страниц и кортежей. Было замечено, что при несовпадении контрольных сумм страниц с их содержимым, pg_filedump выводит соответствующее предупреждение, однако возвращает нулевой код возврата. Что как бы не совсем правильно, особенно если утилита используется в shell-скриптах.


Патч исправляет эту ситуацию. Теперь pg_filedump возвращает ненулевой код при обнаружении любых ошибок, как в контрольных суммах, так и любых других:


+/* Program exit code */
+static int exitCode = 0;
+
 /***
  * Function Prototypes
  */
@@ -191,6 +194,7 @@ ConsumeOptions(int numOptions, char **options)
                        {
                                rc = OPT_RC_INVALID;
                                printf("Error: Missing range start identifier.\n");
+                               exitCode = 1;
                                break;
                        }

@@ -205,6 +209,7 @@ ConsumeOptions(int numOptions, char **options)
                                rc = OPT_RC_INVALID;
                                printf("Error: Invalid range start identifier <%s>.\n",
                                           optionString);
+                               exitCode = 1;
                                break;
                        }

(...и так далее...)

@@ -1746,5 +1823,5 @@ main(int argv, char **argc)
        if (buffer)
                free(buffer);

-       exit(0);
+       exit(exitCode);
 }

Патч: 1c9dd6b728810ea7d2f196e6e15064017e4b9eef


12. Улучшение документации о внутреннем представлении типа timestamp


Документация к типу timestamp гласила:


    When <type>timestamp</> values are stored as eight-byte integers
    (currently the default), microsecond precision is available over 
    the full range of values. When <type>timestamp</> values are
    stored as double precision floating-point numbers instead (a
    deprecated compile-time option), the effective limit of precision
    might be less than 6. <type>timestamp</type> values are stored as
    seconds before or after midnight 2000-01-01. [...]

В ходе работы над рассмотренным в следующем раздеде патчем было замечено, что приведенный текст создает неверное представление. На самом деле, по умолчанию timestamp хранит время в микросекундах. Если же пользователь выбрал устаревшее представление в виде чисел с плавающей точкой, тогда действительно время хранится в секундах.


После недолгого обсуждения в рассылке вводящий в заблуждение кусок документации был переписан.


Патч: 44f7afba79348883da110642d230a13003b75f62


13. pg_filedump: частичное восстановление данных


Этот патч был подробно рассмотрен в заметке Пример восстановления таблиц PostgreSQL с помощью новой мега фичи pg_filedump, поэтому здесь я не буду на нем подробно останавливаться. TL;DR версия — теперь при помощи pg_filedump можно восстановить по крайней мере какую-то часть данных из таблицы, даже в случае, если инстанс PostgreSQL не запускается.


Патч: 52fa0201f97808d518c64bcb9696f2a350678aa5


14. pg_filedump: декодирование каталожных таблиц


Как и предыдущему патчу, этому была посвящена целая отельная статья Еще одна новая фича pg_filedump: восстанавливаем каталог PostgreSQL. TL;DR версия для тех, кто все равно не собирается ее читать — раньше pg_filedump не поддерживал некоторые типы, используемые в каталожных таблицах. После применения этого патча стало возможным декодировать таблицы каталога, а следовательно и восстановить схему базы данных, если она нам не известна.


Патч: 5c5ba458fa154183d11d43218adf1504873728fd


15а. Ускорение партицирования: исправление батлнека в find_tabstat_entry() / get_tabstat_entry()


В PostgreSQL 10, который на момент написания этих строк разрабатывается и находится в состоянии фичфриза, была добавлена возможность декларативного партицирования таблиц. То есть, теперь таблицу можно разбить на несколько физических таблиц по хэшу или ренджам. Это было возможно и ранее при помощи наследования таблиц, но было менее удобно и в целом выглядело как грязный хак. Примеры использования декларативного партицирования можно найти здесь и здесь.


Ну вот я и подумал, а создам-ка я побольше (скажем, 10 000) партиций и посмотрю, где будет тормозить. Теме профилирования кода на C/C++ ранее я посвящал целую статью, даже несколько, если считать статьи про DTrace, SystemTap и HeapTrack. Кроме того, на эту тему я делал доклад на HighLoad++ 2016, видеозапись которого лежит на YouTube. Поэтому на описании процесса здесь я подробно останавливаться не буду. Скажу только, что perf top показал два явных батлнека, которые вы можете видеть на иллюстрации в начале данной статьи.


Так вот, патч исправляет первый из этих батлнеков. Оказалось, что статистика по таблицам использует небольшой аллокатор памяти, построенный на списках. Поиск по идентификатору таблицы структуры PgStat_TableStatus, соответствующей таблице, производился путем сканирования этого списка, что работает не очень хорошо, когда таблиц 10 000. Добавление хэш-таблицы, отображающей идентификатор таблицы в указатель на структуру, моментально устранило батлнек.


Патч: 090010f2ec9b1f9ac1124dc628b89586f911b641


15б. Ускорение партицирования: исправление батлнека в find_all_inheritors()


Аналогичная проблема присутствовала и в процедуре рекурсивного поиска всех наследников заданной таблицы. Немногие знают, что PostgreSQL поддерживает множественное наследование таблиц. Поэтому при обходе дочерних таблиц процедура проходит по списку ранее посещенных таблиц. Если очередной таблицы в списке нет, она в него добавляется. Если она там уже есть, у таблицы увеличивается счетчик родителей. Список всех дочерних таблиц и число их родителей возвращается из процедуры в качестве результата.


Как вы уже могли догадаться, батлнек снова был устранен добавлением хэш-таблицы для ускорения поиска по списку. По моим бенчмаркам два патча суммарно ускорили декларативное партицирование на 64%. Интересно, что патчи ускоряют его не только при большом количестве партиций, но и когда партиций всего лишь несколько штук. Хотя в последнем случае, конечно же, эффект не так заметен.


Патч: 827d6f977940952ebef4bd21fb0f97be4e20c0c4


Заключение


Как и ранее, цель всех этих статей — показать, что в разработке РСУБД, в частности PostgreSQL, несмотря на крайнюю интересность процесса, нет чего-то волшебного или прямо-таки непостижимо сложного. Хочется надеяться, что эта серия статей сможет мотивировать пару-тройку человек принять участие в разработке PostgreSQL, в качестве хобби, или же профессионально.


В частности, компания Postgres Professional, в которой я сейчас работаю, перманентно нанимает, притом, не только программистов, но и, к примеру, QA и DBA. Как уже было отмечено, качественные тестирование и code review в нашем деле зачастую оказываются важнее написания кода.

Postgres Professional 131,21
Российский вендор PostgreSQL
Поделиться публикацией
Похожие публикации
Комментарии 19
  • 0
    Можно поинтересоваться — какими GUI-утилитами (если) пользуетесь для работы с PG?
    Есть ли среди что-то хоть отдалённо похожее на SqlYog? (жаль, что он только для Mysql)
    • 0

      Все (ну, многие) JetBrain-овские IDE поставляются с вполне неплохим плагином-клиентом. Standalone тоже есть, DataGrip называется.


      Для OS X еще есть PSequel.

      • 0
        Увы и ах…
        Даже платное ПО такой уважаемой фирмы не имеет возможности вывести список БД на сервере (что изначально есть в бесплатном pgAdmin-е).
        Вопрос поднят больше года назад (https://youtrack.jetbrains.com/issue/DBE-2287)
        «Фича не реализована потому что потому!»
        • 0

          Хм, а чем вы занимаетесь, что это так часто надо? Мне обычно не надо примерно никогда, я знаю, как называется база, с которой мне надо работать.

      • 0
        В настоящее время не пользуюсь никакими.

        Раньше пробовал разные. Советую посмотреть на DataGrip от JetBrains.
        • 0
          То есть как это не пользуетесь?
          Не работаете с БД или работаете исключительно из командной строки?
          • +1
            Все через psql
            • 0

              А как с большими запросами, которые нужно немного поправить, а потом ещё раз запустить? А потом опять слегка поправить и опять запустить?

              • 0
                Ну, например:

                vim query.sql
                :!psql query.sql


                Просто первое, что в голову пришло.
                • 0

                  Я какое-то время так работал — очень утомляло менять параметры соединения (я работаю с разными БД). Также утомляет отсутсвие подсказок и всего такого. Сейчас вот с emacs сижу на sqli (который по сути то, что у вас описано, только выполнение запросов можно делать не из всего файла). Data Grip не пробую из упрямства и нежелания иметь тяжёлую прослойку между мной и psql. Но по-моему рано или поздно все там будем.

        • 0
          Попробуйте Navicat Premium — только он сильно платный. А вообще, pgAdmin, особенно последний, очень даже хорош. К тому же его вполне себе можно поставить ни на свою машину и коннектиться к базам от себя.
          • 0
            В последнее время слышал немало хвалебных отзывов о DBeaver
            • 0
              Обсуждение инструментов для работы с PG:
              https://habrahabr.ru/company/pgdayrussia/blog/325642/
            • –1
              Сегодня пятница, сегодня можно :)
              Скрытый текст


              P.S. ничего против PG не имею, наоборот. Да и вообще Дмитрий занятные вещи говорит.
              • 0
                Извиняюсь, но почему батлнек? Узкое место — это ботлнек, bottle neck.
                • 0
                  В соответствии с произношением — ˈbätl
                  • 0
                    Хм, откуда ваш вариант произношения? Я встречал типа таких: ˈbɒt(ə)lˌnek Вот эта вот ɒ — почти как о в русском.
                    Конечно, можно спорить до бесконечности как надо произносить: как в каком-нибудь уважаемом словаре и по IPA, на каком-нибудь южном американском диалекте или все же используя произношение канадцев. Но если быть последовательным, то нужен вариант батлнэк.
                    Не сочтите, что придираюсь, но просто как пожелание: почему бы не использовать транслит вместо фонетической транскрипции? Транслит пусть и не красит текст, но гораздо привычнее для восприятия, особенно когда батл уже «занят» battle. Ведь вы же используете привычный патч, а не пэтч :)
                    • 0

                      Как не поучаствовать в языковом споре-то.


                      Тут получается, что в UK "ботл", в США и "ботл" и "батл".

                      • 0
                        В macmillan схоже. А есть еще австралийские варианты, новозеландские. И там тоже есть различия: где-то огубленный звук ɒ, где-то нет. А уж в локальных диалектах-то… А если еще и этимологические корни слова вспомнить («о» победит), то получится настоящий холивар :)
                        Я ж не об этом. Транслит давно уже стал нормой в ИТ-текстах. Но есть некоторые непривычные, редковстречающиеся слова, которые воспринимаются как будто написаны с ошибкой. Ну примерно как раутер.
                        И такие слова делают текст легкомысленным, непрофессиональным что ли. Тема-то интересная местами, особенно когда речь про внутренности pg, но воспринимается несерьезно и поверхностно.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое