DISCLAIMER: посыл этой статьи не в том, что «PostgreSQL — плох, не используйте PostgreSQL». Посыл в следующем: «Может быть я чего-то не понимаю в этой жизни? Пожалуйста, объясните, может быть я изменю своё мнение!»


Когда-то в стародавние времена (лет 20+ назад), когда выбирал для себя базовую СУБД, выбор был между MySQL и PostgreSQL, я на них обоих посмотрел и, несмотря на то, что на тот момент PostgreSQL была существенно мощнее конкурента в плане возможностей (поддержка хранимых процедур и далее по списку), я сделал для себя выбор в пользу MySQL, поскольку его SQL-синтаксис мне понравился гораздо больше.

Среди того, что понравилось в MySQL:
Гораздо более развитый DDL (Data Definition Language) и DCL (data control language): SHOW DATABASES, SHOW TABLES, SHOW CREATE TABLE и т.п.

Также приятные плюшки в DML (data modification language) типа REPLACE INTO.

За 20+ лет, в течение которых пользовался MySQL, он существенно повзрослел и возмужал, добавились:

  • поддержка хранимых процедур и функций

  • поддержка общих табличных выражений (CTE)

  • поддержка оконных функций (Window Functions)

  • репликация / кластеризация

  • поддержка различных storage engines

  • поддержка полнотекстового поиска

  • расширенная статистика для оптимизации запросов

  • поддержка JSON

  • и т.д. и т.п.

Сейчас 20 лет спустя жизнь вновь столкнула с PostgreSQL (решил помочь товарищу с его проектом) и решил дать PostgreSQL «второй шанс».
Удивлению моему не было предела, когда 20 лет спустя я столкнулся с тем, что НИЧЕГО из того, что меня напрягало ещё тогда, не улучшено.

Итак, поехали...
Для сравнения, берём последнюю версию PostgreSQL 16.

Data Control Language

MySQL

PostgreSQL

psql shortcut

SHOW DATABASES

SELECT datname FROM pg_database;

\l

SHOW TABLES

SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'

\dt

SHOW CREATE TABLE table_name

SELECT column_name, data_type, character_maximum_length, column_default, is_nullable FROM information_schema.columns WHERE table_name = 'table_name';

\d+ table_name

SHOW VARIABLES

SELECT name, setting FROM pg_settings;

\set

SHOW PROCESSLIST

SELECT * FROM pg_stat_activity;

SHOW STATUS

SELECT * FROM pg_stat_database;

SHOW GRANTS

SELECT * FROM information_schema.enabled_roles;
SELECT * FROM information_schema.role_table_grants WHERE grantee = 'rolename';

\dp

USE dbname

\c dbname

FLUSH PRIVILEGES

SELECT pg_reload_conf();

KILL [CONNECTION | QUERY] thread_id

SELECT pg_terminate_backend(pid);

FLUSH TABLES
FLUSH HOSTS
FLUSH LOGS
FLUSH USER_RESOURCES
и т.п.

нет прямого эквивалента

Сразу ответ на коммент:

В постгре мета-информация хранится в табличках, что очень гибко, ибо позволяет использовать всю мощь SQL для работы с этими данными, а не зазубривать ограниченные кастомные команды

В MySQL также давно появилась служебная базаinformation_schema, из которой также можно извлечь всё что нужно. При этом остаются удобные и легко-запоминающиеся шорткаты SHOW, для тех, кто хочет быстро что-то посмотреть.

Data Definition Language

MySQL

PostgreSQL

ALTER TABLE table_name CHANGE COLUMN old_column_name new_column_name new_data_type;

ALTER TABLE table_name RENAME COLUMN old_column_name TO new_column_name;
ALTER TABLE table_name ALTER COLUMN new_column_name new_data_type;

ALTER TABLE table_name ADD COLUMN col1 int AFTER col2

CREATE TABLE foobar_new ( ... );
INSERT INTO foobar_new SELECT ... FROM foobar;
DROP TABLE foobar;
ALTER TABLE foobar_new RENAME TO foobar;

можно перемещать таблицы между базами данных с помощью RENAME TABLE

Только переносить через дамп

Офигеть, я не могу добавить новую колонку после другой конкретной колонки, а могу добавить только в конец...
Можно только процитировать Тинькова: «ну это п$%дец какой-то, ну как это может быть в 21-м веке...»

Воспринимать серьёзно наезды на невозможность вставки колонки в середину таблицы (расскажите, зачем это может понадобиться, пожалуйста)

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

Data Manipulation Language

MySQL

PostgreSQL

REPLACE INTO

INSERT INTO the_table (id, column_1, column_2) VALUES (1, 'A', 'X'), (2, 'B', 'Y'), (3, 'C', 'Z')
ON CONFLICT (id) DO UPDATE
SET column_1 = excluded.column_1, column_2 = excluded.column_2;

Насколько упрощает жизнь REPLACE INTO, почему это нельзя добавить?

Поддержка JSON

В PostgreSQL два отдельных типа данных для JSON: JSON и JSONB.
При этом с типом JSON нельзя сделать практически ничего, всё вкусное и полезное только в JSONB.
При этом мы имеем чрезвычайно строгий и замороченный синтаксис для работы JSON, с постоянным приведением типов туда/сюда.
Пока писал нужные мне SQL-statements для работы с JSON, пришлось мучать ChatGPT несколько часов подряд, которого я довёл, наверное, до седины — постоянно сыпались те или иные ошибки, интуитивно-очевидные конструкции с JSON не работают.
Да и у меня добавилось седых волос.

Приятно-неприятные мелочи

Удобный вывод записей:

В MySQL можно сделать удобный вывод строк в случае длинных записей / значений:

mysql> SELECT * FROM geoPoints LIMIT 1\G
*************************** 1. row ***************************
         id: 26
        lat: 53.41119462
        lon: 49.91625309
description: Родник № 2 в Каменной Чаше
    ip_addr: 85.113.61.32 
1 row in set (0.00 sec)

В PostgreSQL есть «типа аналог»: \pset format unaligned.
Однако вывод куда менее удобный для визуального анализа:

tgposts=> \pset format unaligned                      
Формат вывода: unaligned.
tgposts=> SELECT * FROM source_posts LIMIT 2;
post_id|channel_id|msg_id|post_date|grab_date|grouped_id|main_msg|post_text|post_media|media_type|media_saved
456|1124038902|51771|2024-05-28 09:29:16|2024-05-29 16:31:19||t|СДЭК намерен восстановить выдачу посылок не позднее 29 мая — заявление компании|||
457|1124038902|51772|2024-05-28 10:29:09|2024-05-29 16:31:19||t|Испания признала независимость Палестины — МИД Испании

upd: Аналогичные решения, согласно заявлениям местных властей, также официально утвердили Норвегия и Ирландия.|||
(2 строки)

Есть ещё \x, но вывод всё равно менее удобный для визуального восприятия, поскольку данные не выровнены по горизонтали:

tgposts=> \x
Расширенный вывод включён.
tgposts=> SELECT * FROM source_posts LIMIT 2;
post_id|456
channel_id|1124038902
msg_id|51771
post_date|2024-05-28 09:29:16
grab_date|2024-05-29 16:31:19
grouped_id|
main_msg|t
post_text|СДЭК намерен восстановить выдачу посылок не позднее 29 мая — заявление компании
post_media|
media_type|
media_saved|

Поправьте в статье, пожалуйста.
Если сначала сделать \pset format unaligned, а потом \x, то, конечно, будет невыровненный вывод. Но если вернуть \pset format aligned, то \x все корректно и красиво выравнивает.

Вот, хоть какая-то практическая польза появилась для меня от статьи помимио справочника эквивалентов SQL-команд. Спасибо! )

"Безопасность должна быть безопасной":

Почему-то в PostgreSQL по умолчанию нельзя аутентифицироваться с паролем.

Вместо этого предлагается «аутентификация по учетным данным операционной системы», которая почему-то считается более безопасной.
Пользователь базы данных должен совпадать с именем учетной записи операционной системы, с которой было установлено соединение. Ну коммон, это неудобно и негибко.

Чтобы входить с паролем, нужно прописывать отдельные разрешения для соответствующих пользователей в pg_hba.conf и перезагружать сервер (или делать
SELECT pg_reload_conf()).

Необходимость вакуумирования:

В PostgreSQL есть необходимость периодического вакуумирования.
Как нам объясняет ChatGPT, основные причины, по которым требуется вакуумирование в PostgreSQL:

  • Очистка старых версий строк

  • Обновление статистики таблиц

  • Защита от bloat (разбухания) индексов

  • Поддержка работы MVCC MySQL все основные storage engines как-то сами решают эти проблемы без необходимости об этом отдельно беспокоиться.

И это лишь «верхушка айсберга», со сколькими ещё сюрпризами мне предстоит столкнуться?....

Почему всё так грустно и неудобно?

Спросил об этом ChatGPT:

почему в Postgres отсутствует ряд возможностей (о которых я спрашивал ранее), которые есть при этом в MySQL?

вот что он / она / оно пишет:

Философия разработки:
PostgreSQL и MySQL имеют разные философии и подходы к разработке. PostgreSQL делает акцент на строгом следовании стандартам SQL и обеспечении высокой надежности и целостности данных, даже если это означает отказ от некоторых нестандартных или потенциально небезопасных возможностей.
MySQL, с другой стороны, больше ориентирован на производительность и гибкость, что иногда приводит к внедрению нестандартных языковых конструкций.

Ну хорошо, тезис со «строгой поддержкой стандартов» услышан.
Допустим, PostgreSQL так трепетно блюдёт стандарты и не добавляет ничего нестандартного...
Что же мы видим в реальности?

Видим, к примеру, ВСТРОЕННУЮ (не в виде отдельного модуля, а встроенную в core-функциональность) масштабную поддержку работы с геоданными, причём для неё определена куча отдельных пунктуационных операторов, к примеру:

SELECT geom1 && geom2; -- Возвращает true, если геометрии пересекаются
SELECT geom1 << geom2; -- Возвращает true, если geom1 полностью находится внутри geom2
SELECT geom1 >> geom2; -- Возвращает true, если geom2 полностью находится внутри geom1
SELECT geom1 &< geom2; -- Возвращает true, если геометрии пересекаются или одна находится внутри другой
SELECT geom1 &> geom2; -- Возвращает true, если геометрии пересекаются или одна содержит другую
SELECT geom1 <-> geom2; -- Возвращает расстояние между геометриями
SELECT geom1 @ geom2; -- Возвращает true, если geom1 находится внутри geom2
SELECT geom1 ~ geom2 @> distance; -- Возвращает true, если расстояние между геометриями меньше или равно distance
SELECT parallel(lseg '[(0,0),(2,2)]', lseg '[(1,1),(3,3)]'); -- Проверка параллельности отрезков, вывод: true
SELECT parallel(lseg '[(0,0),(2,2)]', lseg '[(1,0),(3,2)]'); -- Проверка параллельности отрезков, вывод: false

Хм, где же тут поддержка стандартов?
И где целесообразность и логика: как, например, быть с допусками при проверки параллельности прямых? Ведь в реальности при дискретном представлении данных прямые практически никогда не бывают параллельными, если только они не параллельны сетке координат...
Да, в PostGIS есть для этого более вменяемая функция ST_ParallelWithTolerance, но тогда зачем вообще нужна эта функция parallel в core-функционале, если она по этой причине по определению мертворожденная?

Получается, сделать поддержку SHOW TABLES или SHOW DATABASES или ADD COLUMN AFTER — религия не позволяет, а запоминать всякие однобуквенно-двухбуквенные костыли вроде \l \dt \d+ \dp или каждый раз писать портянку вроде

SELECT column_name, data_type, character_maximum_length, column_default, is_nullable
FROM information_schema.columns 
WHERE table_name = 'table_name';```

вместо SHOW CREATE TABLE или

INSERT INTO the_table (id, column_1, column_2) 
VALUES (1, 'A', 'X'), (2, 'B', 'Y'), (3, 'C', 'Z')
ON CONFLICT (id) DO UPDATE 
  SET column_1 = excluded.column_1, 
      column_2 = excluded.column_2;

вместо REPLACE INTO — это более правильный и идеологически-выверенный подход?

Тогда как вы объясните целую россыпь нестандартных пунктуационных операторов (# :: ?@ ? ?. @> <@ && -> #> и т.п.), число которых приближается к сотне и поддержку геоданных (с кучей своих операторов и встроенных функций) в ядре СУБД общего назначения?

Возможно, я просто чего-то не понимаю или просто ChatGPT мне не может адекватно объяснить. Тогда объясните мне, пожалуйста, в комментах, уважаемые читатели, буду весьма благодарен...
А то дожил до седых волос и так и не понимаю причину того, что данная СУБД, является «выбором по умолчанию» для большинства (по моим ощущениям, обгоняя в этом отношении MySQL).
Может быть все вышеперечисленные возможности не нужны или реализуются каким-то иным более удобным способом?
Просветите, пожалуйста!

Комментарии (105)


  1. tuxi
    03.06.2024 14:47
    +4

    Не знаю как сейчас, а 20+ лет назад mysql был рекордсменом по минимальному времени выполнения insert, причем с большим отрывом от 2го места. Интересно как сейчас дела обстоят.


    1. Kerman
      03.06.2024 14:47
      +10

      20+ лет назад там был myisam, так что неудивительно. Да, был был быстрый инсерт, но в ущерб надёжности, транзакционности и прочим "ненужным" вещам. Сейчас с InnoDb всё примерно как у всех. Зависит от сценария, ключей, индексов, хранилища, памяти.


      1. tuxi
        03.06.2024 14:47

        Ну это понятно, что без транзакций. Но другие доступные бд сравнивались тоже с отключенными транзакциями. В 2002..2003 году делали свою ORM и там требовалось писать event log быстро, практически как пишет счетчик посещения страниц. Вот mysql победил просто с громадным отрывом. Помню, что даже какую то файловую бд тестили.


    1. Politura
      03.06.2024 14:47
      +3

      20 лет назад там там не было транзакций, оттого и была самая быстрая запись.

      Думаю, теперь, как повзрослела, уже не самая быстрая.


      1. Tzimie
        03.06.2024 14:47

        Скажите у MSSQL delayed durability и он тоже так будет.


      1. galaxy
        03.06.2024 14:47

        С учетом потабличных блокировок при UPDATE (и некоторых INSERT) быстрая запись там специфическая (myisam).

        При сколько-нибудь существенной concurrency от нее ничего не останется.


  1. BogdanPetrov
    03.06.2024 14:47
    +5

    Спасибо за сравнение, увидел для себя отдельные интересные моменты. Но, честно говоря, немного поверхностно получилось, ничего критичного не увидел (а хотелось бы). Я MySQL не пользовался и все перечисленное не вызывает особых вопросов.


  1. Pitkin_zadov
    03.06.2024 14:47
    +11

    Вы просто увидели серьезную СУБД, а не это вот всё :).
    Сравните MySQL например с MSSQL или Oracle. Будет тоже самое, если не хуже.


    1. Kerman
      03.06.2024 14:47

      О, как. MySql оказывается несерьёзная. И в каком месте она несерьёзная?

      Если стоит задача хранить реляционные данные и получать к ним доступ, то чем плоха MySql? Я вот по наивности считал, что именно хранение данных - это первейшая задача СУБД.

      Тот же оракл не имеет интовых типов данных. Да, там есть INTEGER, для совместимости с SQL'92, но это тот же самый number(0, 38). То есть число с переменной длиной, которое не запихнёшь с гарантией ни в один из типов современных бэкенд-языков. Это признак серьёзности?

      Да, ни оракл, ни постгрес, ни mssql не умеют в add column after. У всех отмазка "ну это чтобы не пересоздавать таблицу". Мне пофиг на пересоздание, у меня там три записи (или вообще нет ни одной). Почему я не могу встроенным синтаксисом вставить столбец куда мне надо? Да, мне это важно, потому что я сортирую столбцы по их назначению. Мне потом их проще искать.

      Почему у оракла 30к символов ограничение в nvarchar (при флаге extended, без него 12к)? Это из серии "640кб хватит всем"? Не, я понимаю, что можно пихать текст в блобы, никто вроде не запрещает. Но у того же мускуля 64к символов в TEXT и 4ккк символов в LONGTEXT. Неужели сложно?


      1. MrNutz
        03.06.2024 14:47
        +4

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


        1. Kerman
          03.06.2024 14:47

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

          БД - инструмент разработчика. Разработчик делает инструмент для бизнеса. И позвольте разработчику самому решать, какая должна быть структура данных.

          Я часто работаю с "сырыми" данными в sql, когда надо быстро посмотреть, в каком состоянии находятся объекты. Иногда таблицы довольно большие, 20, 30 и иногда 100+ столбцов. Мне УДОБНО, когда столбцы, относящиеся к одному функционалу находятся рядом, тогда не приходится скроллить таблицу или изобретать вьюшки на каждый случай. А на каждый случай вьюшек не напасёшься.


          1. Zverienish
            03.06.2024 14:47

            Если вам часто приходится работать с сырыми данными, значит что-то с работой у вас не так.


      1. volos4
        03.06.2024 14:47

        NS SQL management studio умеет в add column after. ваша правда - через пересоздание таблицы, индексов и копировании. данных. н для польщователя этот процесс прозрачный если количество строк невелико.

        есть ли гарантия того что mysql не делает тоже самое - insert column через пересоздание таблицы?


        1. Kerman
          03.06.2024 14:47

          MySql делает это ТОЧНО через пересоздание таблицы. Что я прекрасно знаю и это меня ничуть не волнует.


          1. ptr128
            03.06.2024 14:47

            Через пересоздание любая СУБД умеет. Различия лишь в размерах синтаксического сахара для этих целей. Напишите себе процедуру, которая добавляет поле не в конец таблицы через её пересоздание и радуйтесь.


            1. Kerman
              03.06.2024 14:47

              Плюс к этой процедуре надо написать интерфейс для удобного редактирования структуры таблицы, чтобы можно было драгдропом поменять местами колонки. Потом механизм сопоставления версий структур данных для генерации миграций. Ну и сразу удобный data management, чтобы можно было в одном месте и данные в таблице поменять )

              Хорошая идея. Я этим как раз и занимаюсь. Но это дорого и долго.


              1. gudvinr
                03.06.2024 14:47
                +2

                чтобы можно было драгдропом поменять местами колонки

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


                1. Kerman
                  03.06.2024 14:47

                  Да, классная фича, оценил. В своё время я отказался от DG из-за одной "фигни", которая критична для меня. Мне нужен список полей с комментариями внутри таблицы. Этого в DG нет или я не нашёл.

                  Мне понравилось, как именно перетаскиваются колонки. Прямо вместе с мясом. Я себе так же сделаю.


      1. gudvinr
        03.06.2024 14:47

        Почему я не могу встроенным синтаксисом вставить столбец куда мне надо? Да, мне это важно, потому что я сортирую столбцы по их назначению. Мне потом их проще искать.

        Так сделайте view для таблицы и отдельно таблицу. Это будет работать вообще в любой БД.
        Более того, в постгре и mysql можно ещё и update делать на таких view.

        Почему у оракла 30к символов ограничение в nvarchar (при флаге extended, без него 12к)? Это из серии "640кб хватит всем"?

        Почему у мускуля 4ккк символов ограничение в TEXT (в LONGTEXT, без него 64к)? Это из серии "640кб хватит всем"?

        1. NVARCHAR определяет кол-во символов - это 2x32k БАЙТ для UTF16 и 3x32к для UTF8, а TEXT в MySQL - это 64k БАЙТ. Причём, в случае с азиатскими символами, символов в TEXT влезет меньше, чем в NVARCHAR т.к. в UTF16 они занимают 2 байта, а в UTF8 - 3. А русскоязычными текстами разницы не будет никакой. Поэтому не всё так однозначно.

        2. В CLOB (не BLOB) можно запихнуть 8+ терабайт текста, если очень надо


        1. Kerman
          03.06.2024 14:47

          Я упорядочиваю столбцы по их функционалу для того, чтобы снизить когнитивную нагрузку при работе с данными, а вы предлагаете насоздавать вьюшек на каждую большую таблицу, чтобы потом следить за соответствием этих вьюшек таблицам. Я не враг себе, мне такие костыли не нужны.


          1. gudvinr
            03.06.2024 14:47
            +3

            мне такие костыли не нужны

            Если вас настолько волнует представление - это не проблема БД, а проблема инструментов, которые вы используете для просмотра БД.
            Поэтому переупорядочивание колонок внутри БД - это костыль, который вы используете чтобы пофиксить проблему инструмента.


            1. Kerman
              03.06.2024 14:47

              Это проблема БД, потому что она хранит структуру таблиц. Внешние инструменты будут вынуждены синхронизироваться с ней и хранить данные о порядке вне структуры.

              В любом случае есть факт. MySql позволяет встроенным синтаксисом менять расположение колонок, а оракл/мс/постгрес - нет. Вот и всё. Не надо мне доказывать, что мне это не нужно. Не надо предлагать костылями подпереть. Не надо скидывать ответственность на другие инструменты.


              1. ptr128
                03.06.2024 14:47

                Это проблема БД, потому что она хранит структуру таблиц. Внешние инструменты будут вынуждены синхронизироваться с ней и хранить данные о порядке вне структуры.

                Ну так храните пользовательский порядок полей в БД. Например, начинайте комментарий к полю с числа с ведущим нулем, определяющим порядок отображения поля.


              1. gudvinr
                03.06.2024 14:47
                +2

                А что делать, если вы не одинокий волк с уолл стрит, а работаете на работе? Ну знаете, это такое место где ещё другие люди есть.
                И у других людей есть своё представление о прекрасном.

                Почему ваше представление должно быть единственно правильным и ему должны следовать другие люди? Причем речь именно о визуальном представлении на вашем мониторе, которое абсолютно ни на что не влияет, кроме ваших приколов.

                Не надо скидывать ответственность на другие инструменты.

                Так и не скидывайте ответственность за вывод на экран на базу данных :)


                1. Kerman
                  03.06.2024 14:47

                  Почему ваше представление должно быть единственно правильным

                  А и не должно быть. Это вообще-то подмена тезиса. Я говорю про ВОЗМОЖНОСТЬ упорядочивания колонок, а вы мне про эгоцентризм. Если работаешь с людьми - тогда учитывай интересы людей.

                  Я обычно работаю над проектом один, и в этом режиме мне абсолютно плевать на мнение коллег о структуре данных.


                  1. gudvinr
                    03.06.2024 14:47

                    Так ВОЗМОЖНОСТЬ есть и в оракле и в постгресе. Ну да, допустим она реализуется не одной командой а тремя, но вам никто не запрещает.


                    1. Kerman
                      03.06.2024 14:47

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

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


                      1. GlukKazan
                        03.06.2024 14:47

                        При желании, всё это можно автоматизировать и выполнять одной строкой. Только зачем?


                      1. gudvinr
                        03.06.2024 14:47

                        Не тремя. Даже не десятью.

                        Пожалуйста:

                        1. Создаём таблицу

                        create table X (
                        	id          bigint generated always as identity,
                        	given_name  text not null,
                        	family_name text not null
                        );
                        
                        1. Добавляем новые столбцы и копируем данные из старых

                        alter table X
                        	add column patronymic text,
                        	add column _family_name text not null generated always as (family_name) stored;
                        
                        1. Удаляем старый столбец

                        alter table X
                        	alter column _family_name drop expression,
                        	drop column family_name;
                        
                        1. Переименовываем временный столбец

                        alter table X
                        	rename column _family_name to family_name;
                        


          1. Zverienish
            03.06.2024 14:47

            А зачем вы с данными работаете в таком количестве? Да мне приходится залазить в базу чтобы что-то проверить парни разработке, но это мизер времени занимает и посмотреть в сыром виде не проблема. А так делайте тесты на работу с бл и не придется проверять все.


      1. galaxy
        03.06.2024 14:47
        +2

        Да, ни оракл, ни постгрес, ни mssql не умеют в add column after. У всех отмазка "ну это чтобы не пересоздавать таблицу"

        Ну у постгреса отмазка скорее "мы не против, просто геморроя оказывается многовато для такой малоактуальной фичи, и никто пока не заморочился аккуратно сделать". Вот, например, подход к снаряду 2014 года - почитайте простыню, если интересно, почему не шмогли.

        Мне пофиг на пересоздание, у меня там три записи

        Вот и делайте через пересоздание таблицы (или через добавление/удаление колонок, как в статье выше описано).

        Нет и нет этой фишки, штука явно не ключевая для СУБД, чего срач разводить.


      1. Zverienish
        03.06.2024 14:47

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


    1. tuxi
      03.06.2024 14:47
      +3

      Ну назвать мускуль несерьезной бд - это тоже не совсем верно. Просто считается, что раз ее пользуют в куче хоум-пет проектов "сайт 30 страничек на коленке", то это типа несерьезно. Но я видел проекты, где мускуль держал серьезные обьемы данных.


  1. panzerfaust
    03.06.2024 14:47
    +30

    Зашел почитать про сравнение производительности индексов, инсертов и апдейтов, а прочитал про то, что алиасов не завезли.


    1. Zverienish
      03.06.2024 14:47

      Да, а написана чистая вкусовщина человека который видимо весь день сидит в консольке и строчит запросы.


  1. ky0
    03.06.2024 14:47
    +5

    В чём вопрос? Почему СУБД, обладающая объективными преимуществами, но неудобная для вас по каким-то мелочам, популярнее?

    Воспринимать серьёзно наезды на невозможность вставки колонки в середину таблицы (расскажите, зачем это может понадобиться, пожалуйста), вакуум, какое-то там форматирование консольного вывода и на неудобные настройки аутентификации по умолчанию - сложновато.


    1. despair Автор
      03.06.2024 14:47

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


      1. gudvinr
        03.06.2024 14:47
        +9

        Если очень хочется двигать поля зачем-то, то это сделать можно.
        Если хочется чтоб красиво выглядело - можно просто view поверх таблицы сделать, и это будет работать в любой бд


      1. ky0
        03.06.2024 14:47
        +6

        Что такое "поля, сгруппированные по смыслу"? Какую прикладную пользу для работы СУБД эта группировка несёт?

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


        1. imanushin
          03.06.2024 14:47
          +3

          Возможно, это следствие какой-нибудь ошибки в дизайне приложения, в стиле «мы используем ‘select * from …’, а поля присваиваем по индексу ради производительности».


        1. mentin
          03.06.2024 14:47

          Я думаю автор хочет просто логически группировать по смыслу, и в процессе эволюции схемы добавлять рядом с "близкими" полями, чтобы в UI они рядышком были. Скажем, у пользователя есть поля регион, город, улица, номер_дома, мы вышли на международный рынок и хотим добавить страну перед регионом. Для СУБД никакой пользы, для человека - удобство.

          Это уж безотносительно того, что менять состав полей на работающей продукционной системе - вообще так себе затея.

          А что делать? :) Постоянно в софте только то, что он постоянно меняется. К счастью, разработчики баз данных это понимают, и добавление колонки нынче почти всегда мгновенно и не требует остановки базы данных.

          Совместно с SELECT * добавлять колонки не в конец довольно опасно, в конец колонки добавлять гораздо безопаснее. Надо очень аккуратно писать чтобы добавление в середину ничего не поломало. Но в принципе, полезная операция для поддержания таблицы в аккуратном состоянии.


        1. Antohin
          03.06.2024 14:47
          +2

          Кажется я знаю ответ про прикладную пользу от порядка полей. Буду говорить про oracle, к postgres это скорее всего тоже применимо, но видимо со своими нюансами.

          Выделение места в блоке для новой строки зависит от типа полей и их порядка: под null'овые значения типов date и number резервируется место если они "в середине" строки, т.е. за ними не-null-овое значение, и не резервируется если они в конце. Поэтому если у нас есть столбцы в которых мало значений, то сдвинув их в хвост мы сэкономим место. С другой стороны если поле изначально пустое, но рано или поздно будет заполнено, то возможно места в блоке уже не хватит и или хвост строки уедет в другой блок (chained rows) или вся строка. А это и накладные расходы в моменте и дальнейшее замедление доступа в случае chained rows.

          В ситуации когда у нас таблица с кучей малозаполненных полей в "хвосте" и мы добавляем not null столбец в конец, длина строки может вырасти в разы. Если это какая-то огромная таблица, это может быть заметно и больно.


          1. GlukKazan
            03.06.2024 14:47

            экономия на спичках


          1. stvoid
            03.06.2024 14:47

            Ну, вот помимо нелепого аргумента про "логическое упорядочивание" (хотя я понимаю смысл зачем это люди хотят, но это не имеет смысла по факту) вот это конечно... Вроде как и смысл есть, а вроде как самое яркое проявление ОКР в IT


          1. ptr128
            03.06.2024 14:47

            под null'овые значения типов date и number резервируется место

            Не скажу про Oracle, но в PostgreSQL место не резервируется, так как значения полей с NULL значением в кортеже просто отсутствуют. А уж есть значение nullable полей или нет определяется битовой маской в заголовке кортежа.

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


          1. ky0
            03.06.2024 14:47

            Да, вы всё правильно говорите - но такой глубокий анализ, помноженный на размеры БД, при которых эта экономия актуальна, подразумевает столь же скиллованных ДБА/ДБД, от которых странно ждать постоянного изменения набора полей :)


          1. astentx
            03.06.2024 14:47

            Так ровно по этой причине оракл не может вставить колонку в середину, иначе придется перелопатить все данные и устроить в них chained rows. Так как СУБД все же стала уделом программистов, и запросы типа select * не частые гости в UI (или как минимум являются бомбой замедленного действия), то порядок колонок после добавления чаще всего мало кого волнует. Если очень хочется навести порядок и использовать магию с наллами, то есть как альтернативные способы хранения разреженных данных, так и online redefinition. А вот как в MySQL реализована вставка колонки в середину при конкурентных апдейтах/инсертах и насколько оно действительно хорошо работает - интересный вопрос.


            1. Akina
              03.06.2024 14:47

              А вот как в MySQL реализована вставка колонки в середину при конкурентных апдейтах/инсертах и насколько оно действительно хорошо работает - интересный вопрос.

              Начиная с версии 8.0.29, вставка дополнительного поля в любое место InnoDB-таблицы может использовать INSTANT алгоритм и не требует ребилда таблицы. В более старых версиях это верно только для случая добавления поля в конец структуры.

              Что же до последующих DML, то местоположение поля в структуре не влияет - вообще.


              1. ptr128
                03.06.2024 14:47

                может использовать INSTANT алгоритм и не требует ребилда таблицы

                А можно подробней? Метаданные что-ли в каждом кортеже сохраняет?


                1. Akina
                  03.06.2024 14:47

                  Эээ... поподробнее я даже в Internals не нашёл. Это надо смотреть исходники на предмет того, как точно выглядит структура записи в блоке диска.

                  Но я просто попробовал - создал таблицу на 2 varchar, положил пару записей, затем вставил между имеющихся третье поле, вставил ещё запись и обновил существующую. А потом посмотрел в гексах. И вижу, что хоть поле вставлено и между двумя существующими, но в тело данных пишется так, словно вставка выполнена в конец структуры. В обеих записях с не-NULL значением третьего поля.

                  То есть MySQL просто-напросто в метаданных хранит то, как порядок полей таблицы должен выглядеть для пользователя. А реально хранит по-своему.

                  Но если использовать INSTANT или COPY, то тело переписывается в соответствии с заданным порядком полей.


                  1. ptr128
                    03.06.2024 14:47

                    Спасибо! Получается, MySQL отдельно ведет физический и логический порядок колонок. Вот только порядок полей определяет не только их сортировку в списке, но так же оптимизирует размер кортежа выравниванием. И вторая цель недостижима без полного перестроения всех кортежей при добавлении нового поля не в конец кортежа.

                    А первую цель можно достигнуть либо пользовательской таблицей, обновляемой в event trigger, либо сортируя по комментариям колонок, размещая в них логический порядок полей в качестве префикса к собственно комментарию.


                    1. Akina
                      03.06.2024 14:47

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

                      Вот чего ни разу не видел в MySQL - так это дырок в теле записи в файле ради выравнивания. И, поскольку в RM уделено достаточно немало вопросу расхода дисковой памяти, ограничениям и точным (!) расчётам размера записи, а также связанным ограничениям, но при этом нигде нет ни слова ни о порядке записей, ни о выравнивании, то я подозреваю, что выравнивание просто не используется. Всё пишется вплотную, без зазоров, минимизируя расход памяти (и дисковой, и оперативной). Впрочем, не скажу за блоки метаданных. А блоки переполнения по определению монопольны для записи.


                      1. ptr128
                        03.06.2024 14:47

                        Вот чего ни разу не видел в MySQL - так это дырок в теле записи в файле ради выравнивания.

                        В PostgreSQL наоборот, этому уделяется большое внимание. Операции с невыровненными данными могут заметно терять в производительности.

                        точным (!) расчётам размера записи

                        Непонятно, как считать размер записи, если он зависит не только от полей переменной длины, но так же от того, NULL значение у поля или нет. В PostgreSQL так же добавляется TOAST. То есть в зависимости от данных поля они могут быть inline или в таблице TOAST, сжатыми или нет.


      1. mentin
        03.06.2024 14:47
        +2

        Во многих ситуациях в PostgreSql для этого можно использовать TYPE - логически сгруппированные поля засунуть в общий композиционный тип, и добавлять новые поля в него, а не в схему основной таблицы.

        postgres=# create type my_type as (a int, b int);
        CREATE TYPE
        postgres=# create table my_table (x int, y my_type, z int);
        CREATE TABLE
        postgres=# alter type my_type add attribute c int;
        ALTER TYPE
        postgres=# insert into my_table values (1, (2, 3, 4), 5);
        INSERT 0 1
        postgres=# select * from my_table;
         x |    y    | z 
        ---+---------+---
         1 | (2,3,4) | 5
        (1 row)
        


  1. nin-jin
    03.06.2024 14:47
    +5

    Ок, объясняю:

    • В постгре мета-информация хранится в табличках, что очень гибко, ибо позволяет использовать всю мощь SQL для работы с этими данными, а не зазубривать ограниченные кастомные команды.

    • Мутирующие операции через SELECT - это зашквар, конечно, но не критичный.

    • ON CONFLICT более гибок. А гибкость эта нужна. Например, поле created_time обновлять не надо, а updated_time - надо.


    1. despair Автор
      03.06.2024 14:47
      +1

      В MySQL также давно появилась служебная база`information_schema`, из которой также можно извлечь всё что нужно. При этом остаются удобные и легко-запоминающиеся шорткаты SHOW, для тех, кто хочет быстро что-то посмотреть.


      1. baldr
        03.06.2024 14:47
        +4

        удобные и легко-запоминающиеся шорткаты SHOW

        Куда уж короче чем "\l", "\d", "\dn".. ?

        SHOW нет в ANSI SQL - это такая же отсебятина движка, как и шорткаты в postgresql.


        1. Akina
          03.06.2024 14:47
          +1

          Запросы SHOW - это всего лишь набор предопределённых представлений. Так что нет тут никакой "отсебятины движка", есть просто дополнительные инструменты. Весьма удобные для администратора и разработчика.

          Ведь те же дополнительные модули в составе Постгресса (геомодуль или там модуль линка на внешний сервер), отсутствующие в ANSI SQL, вам не приходит в голову называть отсебятиной?


      1. panzerfaust
        03.06.2024 14:47
        +9

        для тех, кто хочет быстро что-то посмотреть

        Кто эти люди? ДБА? Мне, разработчику, эта кухня нужна была пару раз. Еще раз понадобится - один хрен буду гуглить "как сделать ХХХ в YYYSQL". От наличия алиасов вот ни холодно ни жарко.

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


    1. despair Автор
      03.06.2024 14:47

      В MySQL также давно появилась служебная базаinformation_schema, из которой также можно извлечь всё что нужно. При этом остаются удобные и легко-запоминающиеся шорткаты SHOW, для тех, кто хочет быстро что-то посмотреть.


      1. GlukKazan
        03.06.2024 14:47
        +3

        Можно ещё 10 раз повторить.


  1. Akina
    03.06.2024 14:47
    +3

    Ну с большинством того, что перечислено в статье, я в принципе даже готов мириться.

    Но вот от чего я реально зверею - так это от отсутствия SHOW CREATE {object}. Выгрузка через pg_dump или иные способы - это всё костыли, причём местами очень даже кривые. Попробуйте получить полный CREATE TABLE, не требующий последующих ALTER TABLE и CREATE INDEX!

    А ещё мне категорически не понравилась невозможность в ON CONFLICT обрабатывать событие дублирования при наличии нескольких ограничений уникальности. Сталкивался, правда, всего один раз, но видели бы вы, какого монстра пришлось рожать!

    А вот в MySQL явно нехватает общепринятого понятия SCHEMA - тут оно просто алиас DATABASE. И очень неудобна литеральная, а не флаговая, обработка привилегий при работе с GRANT/REVOKE - и это при том, что в mysql.user оно всё разобрано.

    Впрочем, на то, что есть в одной СУБД и отсутствует в другой, можно жаловаться долго.


    1. yegreS
      03.06.2024 14:47
      +1

      В Postgresql появилась новая операция MERGE, она гораздо более гибкая чем ON CONFLICT https://www.postgresql.org/docs/current/sql-merge.html


  1. cadmi
    03.06.2024 14:47
    +1

    Напомните, пожалуйста, как в mysql базу переименовать?


    1. Akina
      03.06.2024 14:47
      +2

      Нет такой фамилии...


      1. cadmi
        03.06.2024 14:47
        +1

        Я думаю, что все поняли, что это был легкий троллинг автора с его

        > можно перемещать таблицы между базами данных с помощью RENAME TABLE

        Но он предпочел проигнорировать вопрос, ведь в качестве ответа придется писать принятый у любителей mysql башизм "сделать запрос к information_schema, получить список всех таблиц, создать новую базу и прокрутить в цикле по именам таблиц RENAME TABLE из старой базы в новую".

        А если серьезно, то эта "богатая возможность" (переносить таблицы между базами) - всего лишь следствие отсутствия namespace isolation у мурсиков. Это не фича, на самом деле, а проблема. Но кого это волнует, ведь зато есть удобные  SHOW DATABASES;


  1. posledam
    03.06.2024 14:47
    +2

    Что же выбрать, качественную и надёжную подвеску, или бардачок для перчаток? Блин, какой сложный выбор.


    1. BackDoorMan
      03.06.2024 14:47

      Подвеска в Жигулях или бардачок в них же. Когда давно есть Мерседесы


      1. alextrof94
        03.06.2024 14:47

        Коли, говорите, что есть Мерседесы - называйте их.