Моя идея - реализовать базовые «векторные часы», где временные метки основаны на часах, всегда идут вперед и гарантированно будут уникальными.Как создать уникальные метки времени в PostgreSQL?
Например, в простой таблице:
CREATE TABLE IF NOT EXISTS timestamps (
last_modified TIMESTAMP UNIQUE
);
Я использую триггер, чтобы установить значение временной метки перед вставкой. Это в основном просто идет в будущее, когда две вставки прибывают в то же самое время:
CREATE OR REPLACE FUNCTION bump_timestamp()
RETURNS trigger AS $$
DECLARE
previous TIMESTAMP;
current TIMESTAMP;
BEGIN
previous := NULL;
SELECT last_modified INTO previous
FROM timestamps
ORDER BY last_modified DESC LIMIT 1;
current := clock_timestamp();
IF previous IS NOT NULL AND previous >= current THEN
current := previous + INTERVAL '1 milliseconds';
END IF;
NEW.last_modified := current;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS tgr_timestamps_last_modified ON timestamps;
CREATE TRIGGER tgr_timestamps_last_modified
BEFORE INSERT OR UPDATE ON timestamps
FOR EACH ROW EXECUTE PROCEDURE bump_timestamp();
Я тогда запустить огромное количество вставок в двух отдельных клиентов:
DO
$$
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO timestamps DEFAULT VALUES;
END LOOP;
END;
$$;
Как и следовало ожидать, я получаю столкновения:
ERROR: duplicate key value violates unique constraint "timestamps_last_modified_key"
État SQL :23505
Détail :Key (last_modified)=(2016-01-15 18:35:22.550367) already exists.
Contexte : SQL statement "INSERT INTO timestamps DEFAULT VALUES"
PL/pgSQL function inline_code_block line 4 at SQL statement
@rach suggested смешивать current_clock()
с SEQUENCE
объекта, но это, вероятно, означает, избавившись от TIMESTAMP
тип. Хотя я не могу понять, как это решит проблему изоляции ...
Есть ли общий шаблон, чтобы этого избежать?
Спасибо за ваши идеи :)
Что случилось только с последовательностью? Вам действительно нужно время? Как насчет использования ключа на 2 столбцах (временная метка, последовательность)? В противном случае у вас есть VU UUID. – jcaron
Почему вы просто не используете 'now()'? 'INSERT INTO timestamps now();' или установить значение по умолчанию этого поля как 'now()', в конце вы не можете вставлять значения duplicate now() при изменении каждой транзакции. – Solrac
@SolracRagnarockradio, любые множественные вставки внутри одной и той же транзакции будут иметь одну и ту же метку времени. Также не уверен, что микросекундная точность временных меток гарантирует разные значения. – jcaron