Задний план: Я перехожу с postgreSQL на Vertica и обнаружил, что есть некоторые проблемы в столбцах IDENTITY
или AUTO_INCREMENT
. Одна из этих проблем заключается в том, что vertica не может присваивать значения столбцам IDENTITY
или изменять столбец, в котором уже есть данные, в столбце IDENTITY
. Поэтому я создал последовательность и установил уникальное значение столбца по умолчанию:
SELECT MAX(id_column) FROM MY_SCHEMA.my_table;
что составляет 12345
CREATE SEQUENCE MY_SCHEMA.seq_id_column MINVALUE 12346 CACHE 1;
ALTER TABLE MY_SCHEMA.my_table
ALTER COLUMN id_column SET DEFAULT(MY_SCHEMA.seq_id_column.nextval);
ALTER TABLE MY_SCHEMA.log ADD UNIQUE(id_column);
Что работает, как ожидалось. В этом случае у меня деактивирован кеш, поскольку я использую установку с одним узлом, и я хочу, чтобы мой столбец идентификатора был непрерывным. Однако это не вариант для кластерной установки, поскольку необходимая блокировка ведет к узкому месту.
Вопрос: В кластере Vertica с несколькими узлами, как я могу получить доступ к идентификатору последней вставки в сеансе (без дополнительного выбора)?
Например. в postgreSQL я мог бы сделать что-то вроде
INSERT INTO MY_SCHEMA.my_table RETURNING id_column;
который не работает в Vertica. Кроме того, функция Vertica LAST_INSERT_ID()
не работает для названных последовательностей. Я также считаю, что запрос current_value
из MY_SCHEMA.seq_id_column
может давать неправильные результаты из-за кеширования, но я не уверен в этом.
Почему без дополнительного SELECT?
Насколько мне известно, выбор даст правильные значения только после фиксации. Я не могу делать коммит после каждой вставки из-за производительности.
Как уже упоминалось, SEQUENCES не поддерживают LAST_INSERT_ID, и я боюсь попасть в состояние гонки при запросе таблицы SEQUENCES. Я просто хочу иметь первичный ключ последней вставленной записи в сеансе.
Интересно, подойдет ли для этого CURRVAL? F.e. CURRVAL(MY_SCHEMA.seq_id_column)
. Справка. Да ладно, вы беспокоитесь об эффекте кеширования. Уходит
@LukStorms На самом деле, это так. Я пробовал это с двумя параллельными сеансами, и каждый сеанс дает мне правильное (кешированное) значение. Если вы добавите свой комментарий в качестве ответа, вы получите награду.
Спасибо, но, хотя это заманчиво, я пропущу это. Это было бы неправильно. Все, что я сделал, это поискал документацию, основанную на предыдущем опыте работы с другими распределенными СУБД. У меня нет доступа к Vertica. И мне не нравится публиковать ответы, которые я не могу проверить или не знаю, сработает наизусть. Поскольку вы выполнили основную работу, протестировав его, и никто другой не дал достойного ответа, то эти баллы также могут быть возвращены вам. Может быть, вы даже могли бы опубликовать свой собственный ответ. Поскольку сама проблема может быть полезна для других, кто когда-нибудь столкнется с той же проблемой.
Комментарии LukStorms указали мне правильное направление.
Функция NEXTVAL()
(насколько я тестировал) выдает смежные значения в случае, когда их запрашивает один сеанс. Кроме того, при параллельном доступе, если он выдан после вставки, CURRVAL
извлекает кэшированное значение, которое гарантированно уникально, но не обязательно непрерывно. Поскольку я никогда не вызываю NEXTVAL
где-либо еще, как в своем предложении по умолчанию, это решает проблему для меня, хотя могут быть случаи, когда дополнительный вызов NEXTVAL
между вставками увеличивает счетчик последовательности.
Один случай, о котором я могу думать (и который я буду тестировать в будущем), - это то, что произойдет, если для AUTO COMMIT
установлено значение OFF
, что по умолчанию является ON
для драйверов клиента Vertica.
Обновлено:
Кажется, это работает даже с AUTOCOMMIT
, являющимся OFF
(показано с использованием клиентского драйвера vertica-python
, где C
- это соединение, а cur
- курсор):
cur.execute("SELECT NEXTVAL('my_schema.my_sequence');")
cur.fetchall()
--> 1
cur.execute("SELECT CURRVAL('my_schema.my_sequence');")
cur.fetchall()
--> 1
cur.execute("SET SESSION AUTOCOMMIT TO OFF")
cur.execute("SELECT NEXTVAL('my_schema.my_sequence');")
cur.execute("SELECT NEXTVAL('my_schema.my_sequence');")
cur.execute("SELECT NEXTVAL('my_schema.my_sequence');")
cur.execute("SELECT CURRVAL('my_schema.my_sequence');")
cur.fetchall()
--> 4
Однако, похоже, это не изменится во время отката соединения. Так происходит следующее:
C.rollback()
cur.execute("SELECT CURRVAL('my_schema.my_sequence');")
cur.fetchall()
--> 4
Интересно. Я как бы ожидал чего-то подобного, что значение последовательности не будет отменено. И я предполагаю, что вы продолжаете стремиться к количеству. Но, возможно, вы могли бы сохранить стоимость до транзакции. Или получите значение MAX из таблицы. И ИЗМЕНИТЬ последовательность ПЕРЕЗАПУСКОМ после отката? Ссылка здесь
Насколько я понимаю, непрерывные числа приводят к возникновению узких мест из-за глобальных блокировок. Я готов пожертвовать непрерывностью в пользу производительности.
Вы проверяли системную таблицу ПОСЛЕДОВАТЕЛЬНОСТИ? Также не могли бы вы описать, чего вы пытаетесь достичь, получая последний идентификатор вставки?