Конкурентность на уровне строк
Конкурентность на уровне строк в 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 значительно амортизируется.