Как стать автором
Обновить

Как работать с Postgres в Go: практики, особенности, нюансы

Время на прочтение 10 мин
Количество просмотров 128K
Всего голосов 76: ↑73 и ↓3 +70
Комментарии 29

Комментарии 29

На мой взгляд, сила Go в простоте. И это выражается, например, в том, что в Go принято писать запросы на голом SQL (ORM не в чести). Это и преимущество, и источник дополнительных трудностей.

Кем принято, если не секрет? Насколько я вижу — у gorm, к примеру, очень активная и большая аудитория.
Аудитория у gorm, действительно, большая. Я это объясняю только тем, что люди переходя с других языков тащат за собой практику использовать orm.

Но, по разным причинам, в Go чуть меньше распространены orm.

А в целом, у постгри много функциональности, которая слабо покрывается orm'ками: мощные cte, насыщенная система типов, функции для работы индексами, мощная индексация по json (а в 12 версию закоммитили jsonpath www.postgresql.org/docs/12/datatype-json.html#DATATYPE-JSONPATH) и большое кол-во других вещей, которые делают использование orm неразумным.

orm-холивар предлагаю не разводить. Отличный вопрос, мне понравился, спасибо!)
мощная индексация по json

Стоит обратить внимание, что по json просто нельзя собрать статистику.
А база, планер которой работает по весовой схеме, просто не может нормально работать без статистики.


Но надеюсь скоро исправят, здесь smagen писал: http://akorotkov.github.io/blog/2015/09/07/jsonb_statistics/ для 10-ки точно еще актуально.

Спасибо за такое хорошее уточнение!)
мощные cte, насыщенная система типов, функции для работы индексами, мощная индексация по json
Плюс замечательный PL/pgSQL. Мы так вообще отказались от идеи разрешать приложениям лезть в базу с запросами напрямую, только через API, благо и JDBC, и psycopg2 умеют в callable statements/procedures. В результате вся логика изолирована, больше не надо заворачивать семантику в строку (ура!), можно вообще не париться насчет кавычек и экранирования (тайпчекер постгреса сам проверит корректность аргументов), многие вещи можно фиксить в продакшне без пересборки и перезапуска приложений и пр.

Transaction Mode и Prepared Statements это известная проблема, мы просто запретили их на клиенте через prepareThreshold=0.
github.com/lib/pq — pure Go Postgres driver for database/sql. Этот драйвер долгое время оставался стандартом по умолчанию. Но на сегодняшний день он потерял свою актуальность и не развивается автором.


С чего вы это взяли? Кодовая база обновляется, последние обновления несколько дней назад.
На Гитхабе никакой информации о прекращении поддержки нет, да и авторов там не один.
Не развивается. Либо очень медленно.
Вот фикс который я очень давно ждал, так и не дождался. Сильно влияет на производительность.
Использую в результате pgx.
Уходя немного в сторону: я нажал в том PR Approve и одобрил изменения (полагая, что ничего не произойдёт, коненчо). Но нет, моё одобрение появилось в списке ревьюверов.

Это Гитхаб так работает и любой может жать кнопки в любом публичном репозитории?
Не во всех. Видимо так настроили :)
Любой может одобрить PR, но они показываются отдельным списком и не учитываются в подсчете количества необходимых одобрений для мержа

Кроме примера из треда, могу еще вот такой PR показать https://github.com/lib/pq/pull/714. О том, что библиотека заброшена пишут даже люди имеющие статус Collaborator.


Основными людьми, поддерживающими жизнь в библиотеке остаются ребята из cockroachdb. Но, например mjibson пишет


It is indeed sad this has no active maintainers. Open source has its problems.
I don't have permissions to grant permissions so I'm not able to do anything. A few of us from cockroach just asked the last time this was a problem and they gave us commit here. We just keep limping along.

Мне кажется, правильным решением будет пометить библиотеку как deprecated, заархивировать проект и забыть о нём. pgx давно обогнал. А с 4 версии станет совсем хорошо)

Значит буду пробовать новый драйвер. Спасибо.
хочется сказать спасибо Артемию за интересный доклад, т.к. сами внутри прошли весь тот же путь в прошлом году, и добавить, что с момент доклада произошло радостное событие — он подготовил и закинул ПР с поддержкой многосерверности в DSN (https://github.com/jackc/pgx/pull/545) c автопереключением на текущего мастера при проблемах и этот ПР был принят и вмержен в pgx.

Спасибо вам)

github.com/jackc/pgx — именно этот драйвер вы хотите использовать.


Хммм… а GORM использует github.com/lib/pq. Интересно, почему не перешли.

В issue глянул — с ходу не нашел. Возможно еще не осознали, что пора.

С одной стороны, после стольких лет использования Sequel и ActiveRecord — так больно смотреть на гошников, жующих свой кактус простоты с самого нуля.
С другой стортоны, этот же кактус заставляет лучше и глубже разбираться в том, как все работает внутри, что явно плюс!
Добрый день, не понял, почему нужно использовать дополнительно pgbouncer, если в пакете БД для Го уже идет свой пуллер соединений с БД.
Просто потому что приложении много и, даже при использовании пула внутри, все вместе они могут породить соединений больше чем порог деградации.
При штатном режиме работы базы и приложения пул соединений в Go позволяет не порождать новые соединения к базе. А вот при малейшей деградации базы данных пул соединений на стороне приложения исчерпывается и кол-во порождаемых соединений на единицу времени в разы возрастает.

А можете прояснить, какая тут причинно-следственная связь?
Впрочем, я понял. Имеется в виду, что пул не исчерпывается (если он ограничен сверху, то какие проблемы?), а наоборот, пул разрастается.
Я воспринимаю пул как ведро) Мы в него кладём соединения если их не используем и забираем оттуда, когда нужно заиспользовать. Но когда в ведре нет соединений — приходится устанавливать новое соединение с базой.
Потенциальные SQL-уязвимости. Разработчик может забыть или некорректно сделать экранирование.

Вероятность этого остается в pgx. Дело в том, что pgx честно делает Simple Query внутри себя, выполняя экранирование аргументов.
github.com/jackc/pgx/blob/0151aeb3077d63ed90110bc083521f709a5d4fef/query.go#L524
Если в этой функции пойдет что-то не так, то это прямой путь к уязвимостям.
lib/pq делает иначе. При указании в connection string параметра binary_parameters=yes драйвер отправит один запрос, в котором сначала идет Parse query string, затем Bind параметров в бинарном виде.
github.com/lib/pq/blob/master/conn.go#L835
Видно, что далее драйвер честно читает Parse и Bind response от базы, как в сценарии с Extended Query.
Это позволяет разработчику или драйверу не собирать запрос в строку самостоятельно, а передать это все базе.
Спасибо! Вы правы, в данном случае экранирование делает сам драйвер. Я надеюсь найти время, закоммитить в pgx передачу параметров в бинарном виде. Но, кстати, этот протокол не стандартизирован и может быть изменен в следующих версиях постгреса. Впрочем, это не так страшно, так как переезд на новую версию дело долгое и можно будет подготовить драйвер к этому.

Как преимущество, с simple query меньше запросов в сеть и ниже latency)
Спасибо за доклад! Скажите, пожалуйста, рассматривали ли вы для себя пакет go pg? По большей части — это пакет, заточенный именно под Postgres. В нем есть очень приятная фича — это внутренний пакет ORM, который дает вам общий для транзакций и обычных соединений интерфейс, за счет которого можно абстрагировать бизнес логику от инфраструктурного слоя.
> абстрагировать бизнес логику от инфраструктурного слоя.
Так как мы работу с базой делаем сразу отдельным слоем (что-то вроде паттерна repository, но без фанатизма), то необходимости в ORM не возникает. Собственно, из-за того, что gopg чуть переусложнена, не хочется её использова. Ну и опыта с pgx просто больше)
а как вы с repository делаете транзакции в го? был бы очень благодарен за сниппет или ссылку
Flaker, спасибо за материал, не подскажете, как с помощью sqlx импортировать csv в таблицу postgres?
Flaker спасибо за статью. А как решаете вопрос переподключениями при потере соединения? pgx из коробки этого почти не умеет.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.