Обновить

Комментарии 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 одновременно.

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

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

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

Информация

Сайт
www.postgrespro.ru
Дата регистрации
Дата основания
Численность
501–1 000 человек
Местоположение
Россия
Представитель
Иван Панченко