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

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

Давно уже занимаюсь переводом на постгрю. Самое веселое было, когда нам дали Экзадату (оракл на стероидах) и попросили перевести на постгрю. Экзадата хороша тем, что можно быть нубом в sql, не знать, что существуют планы запросов и получать неимоверные быстрые селекты с группировками и прочим. Так вот, нам пришлось перелопачивать абсолютно каждый из нескольких сотен запросов, чтобы это хоть как-то крутилось на постгре. Стоимости лицензий и специального железа ушли, но возникла потребность в классных базистах.

Добрый вечер!

Своё карьеру я начинал PL/SQL разработчиком. В моём случае, нужно было знать как можно больше про планы выполнения и про приёмы написания хорошего SQL-кода.

Мне также доводилось конвертировать запросы из exadata в СУБД PostgreSQL на одном из пилотных проектов. Там было над чем подумать, в том числе и над оптимальной схемой секционирования.

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

Такие запросы можно сконвертировать в СУБД PostgreSQL, но запускать их стоит на асинхронной реплике с выключенным hot_standby_feedback и с max_standby_streaming_delay в -1.

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

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

Если не секрет, какие особенности exadata использовались на проекте? И как сейчас живётся без них в PG?

Заранее спасибо.

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

Большое спасибо за статью.

Но Вы ничего не сказали, что делать с Oracle Advanced Queuing и Advanced Compression.

Что же делать с объектными типами PL/SQL, если они содержат еще и методы, а не только атрибуты?

Что делать с глобальными контекстами?

И куда засунуть в PG Oracle Flashback Archive?

Добрый вечер!

На часть вопросов ответ дан во 2-ой и 3-ей части цикла.

Oracle Advanced Queuing - секция "Использование механизма очередей", статья https://habr.com/ru/company/postgrespro/blog/683748/

В настоящий момент компрессия есть в СУБД Postgres Pro Enterprise, но там данные сжимаются целиком, если создать табличное пространство с опцией WITH (compression=true)

https://postgrespro.ru/docs/enterprise/14/cfs-usage

Объектные типы PL/SQL с методами - секция "Использование PL/SQL коллекций и объектов", статья https://habr.com/ru/company/postgrespro/blog/683748/

Глобальные контексты - секция "Расширение pg_variables", статья https://habr.com/ru/company/postgrespro/blog/679808/

Flashback, к сожалению, в PG отсутствует из-за того, что не хранится история об активных транзакциях в тот или иной момент времени в прошлом. Об этом подробно рассказывается, в частности, на курсе DBA-2 в лекции "Снимки данных"

https://edu.postgrespro.ru/dba2/dba2_03_mvcc_snapshots.pdf

Также об этом говорится в книге "PostgreSQL изнутри"

https://postgrespro.ru/education/books/internals

Спасибо!

Но pg_varibales НЕ позволяет создать константу существующую для нескольких сессий.

Глобальные константы существуют в оракле в SGA - видимы сразу для всех сессий.

Как это реализовать в PG?

Часть кейсов можно заменить immutable функциями : хранят и оченьбыстро отдают значения, меняются execute

Добрый день!

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

а pg_variables имеет опцию а-ля "глобальный / сессионный контекст" ?

Добрый день!

В настоящее время только сессионный.

значит pg_variables умеет в глобально видимую память? только как-то без этой опции?

Пока не умеет.

Модуль pg_variables содержит функции для работы с переменными различных типов. Созданные переменные существуют в течение текущей пользовательской сессии.

https://postgrespro.ru/docs/postgrespro/14/pg-variables

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

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

придётся execute -> commit делать при обновлении значения, возможно, одним из аналогов автономной транзакции, тогда другой процесс увидит новое значение

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

Не подскажете, какие есть подходы к тому, что в PostgreSQL нет глобальных индексов?
Я пока вижу только вариант иметь «глобальную» таблицу вместо индекса, и поддерживать её из кода. Есть ли ещё какие-то опции?

Добрый день!

Да, придётся поддерживать глобальную таблицу, например, с помощью триггеров

текстовый локальный примари кей из двух кусков 'idpartition'||sequence.nextval

Добрый день!

А если требуется искать не по первичному ключу?

это же может быть и просто индекс

Отличная серия статей. Есть ли что-то похожее на переезд с MS SQL на Pg?

Добрый день! Спасибо.

Пока такой серии нет, но, наверное, сделать её можно

Добрый день!

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

Откуда такая информация? Можно ссылки?

Добрый вечер!

В комментарии ниже приведён пример такой ситуации в СУБД Oracle и PostgreSQL

Добрый вечер!

Пусть имеется следующая таблица в СУБД Oracle:

CREATE TABLE merge_test(
 id NUMBER NOT NULL,
 value VARCHAR2(10),
 CONSTRAINT PK_MERGE_TEST PRIMARY KEY (id)
);

Пусть к ней обращаются две сессии с autocommit = off следующим образом:

Первая сессия:

MERGE INTO merge_test d
USING (SELECT 1 id, 'A' value 
	     FROM dual
	    ) s
   ON (d.id = s.id)
 WHEN matched THEN
     UPDATE SET d.value = s.value
 WHEN not matched THEN
     INSERT (d.id, d.value) VALUES (s.id, s.value);

Вторая сессия выполняет запрос ниже, ждёт освобождения блокировки:

MERGE INTO merge_test d
USING (SELECT 1 id, 'B' value 
	     FROM dual
	    ) s
   ON (d.id = s.id)
 WHEN matched THEN
     UPDATE SET d.value = s.value
 WHEN not matched THEN
     INSERT (d.id, d.value) VALUES (s.id, s.value);

Первая сессия делает COMMIT, а во второй сессии запрос завершается с ошибкой:

Error report -
ORA-00001: нарушено ограничение уникальности (CISADM.PK_MERGE_TEST)

А теперь посмотрим на аналогичную ситуацию в СУБД PostgreSQL. Ниже приведена команда создания таблицы:

CREATE TABLE merge_test (
  id bigint NOT NULL,
  value VARCHAR(10),
  CONSTRAINT PK_MERGE_TEST PRIMARY KEY (id)
);

Первая сессия:

BEGIN;

INSERT INTO merge_test AS t
SELECT 1, 'A'
    ON CONFLICT (id)
    DO UPDATE
          SET value = EXCLUDED.value
        WHERE t.id = EXCLUDED.id;

INSERT 0 1

Вторая сессия ждёт снятия блокировки:

BEGIN;

INSERT INTO merge_test AS t
SELECT 1, 'B'
    ON CONFLICT (id)
    DO UPDATE
          SET value = EXCLUDED.value
        WHERE t.id = EXCLUDED.id;

Первая сессия выполняет COMMIT:

COMMIT;

Вторая сессия успешно завершается успешно:

INSERT 0 1

SELECT * FROM merge_test;
 id | value
----+-------
  1 | B

COMMIT;

Ниже приведено содержимое таблицы:

SELECT * FROM merge_test;

 id | value
----+-------
  1 | B

В PostgreSQL тоже сделали MERGE

Добрый день!

Вопрос был не про то, что в PG сделали MERGE, о чём также написано в статьях.

А про то, что в Oracle могут быть ошибки ограничения целостности первичного ключа при работе нескольких MERGE одновременно.

Попросили привести ссылку, я привёл пример.

Кроме того, не все могут сразу обновиться на новую версию СУБД.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий