Перейти к основному содержимому

Конкурентность на уровне строк

Конкурентность на уровне строк в OrioleDB максимально приближена к таблицам PostgreSQL. Тем не менее, существуют некоторые различия, поскольку таблицы в OrioleDB организованы по индексу.

Обновление первичного ключа​

Обновление первичного ключа обычно является редкой и необычной ситуацией в таблице, организованной по индексу. В отличие от обычного обновления, обновление первичного ключа реализуется как последовательность операций удаления и вставки. Конкурентные операции обновления и удаления не могут последовать за этим обновлением и могут привести к ошибке. Смотрите приведенный ниже пример. Во второй сессии возникает ошибка из-за конкурентного обновления первичного ключа в первой сессии.

CREATE TABLE tbl
(
id int4 primary key,
value numeric NOT NULL
) USING orioledb;

INSERT INTO tbl VALUES (1, 0.0);
> BEGIN;
> UPDATE tbl SET id = 2 WHERE id = 1;
UPDATE 1
> BEGIN;
> UPDATE tbl SET value = value + 1 WHERE id = 1;
(ожидание)
> COMMIT;
COMMIT
ERROR: tuple to be locked has its primary key changed due to concurrent update
> ROLLBACK;
ROLLBACK

Следование за цепочкой обновлений​

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

CREATE TABLE tbl
(
id int4 primary key,
value numeric NOT NULL
) USING orioledb;

INSERT INTO tbl VALUES (1, 0.0);
> BEGIN;
> DELETE FROM tbl WHERE id = 1;
DELETE 1
> INSERT INTO tbl VALUES (1, 0.0);
INSERT 0 1
> BEGIN;
> UPDATE tbl SET value = value + 1 WHERE id = 1;
(ожидание)
> COMMIT;
COMMIT
UPDATE 1
> COMMIT;
COMMIT

Выделение идентификаторов транзакций и отношения типа куча​

OrioleDB оптимизирует конкурентность за счет использования виртуальных идентификаторов транзакций (виртуальных XID) для операций, ограниченных исключительно таблицами OrioleDB. Это позволяет избежать накладных расходов на выделение полного идентификатора транзакции PostgreSQL (XID) и связанного с ним журнала WAL, необходимого для отношений типа куча.

Изменение любого отношения heap PostgreSQL в рамках транзакции OrioleDB принудительно вызывает выделение полного XID. Это изменяет путь конкурентного выполнения и сводит на нет оптимизацию виртуального XID.

Накладные расходы на генерацию последовательностей​

Последовательности PostgreSQL основаны на отношениях heap. Использование nextval() изменяет отношение последовательности, что запускает выделение полного XID. Для сохранения оптимизированных механизмов транзакций OrioleDB:

  • Включить кэширование последовательностей: Настроить последовательности с директивой CACHE (например, CREATE SEQUENCE my_seq CACHE 100;).
  • Механизм: Кэширование ограничивает модификацию кучи (и выделение полного XID) единственным вызовом nextval(), который получает блок кэша. Последующие вызовы извлекают значения из памяти сессии.
  • Влияние на рабочую нагрузку: Данная оптимизация может иметь критическое значение для рабочих нагрузок с большим количеством малых транзакций. В больших транзакциях штраф за производительность от единичного выделения XID значительно амортизируется.