Tenho alguns serviços que podem ser executados insert
para inserir novos elementos em uma tabela do meu banco de dados (Postgresql). Então, na visão do banco de dados, muitos insert
s são executados concorrentemente.
Minha pergunta é se é possível manter a ordem de inserção com alguma coluna da tabela.
Por exemplo, existem três insert
s:
INSERT INTO Users (UserName, Id) VALUES ('Tom', 1);
INSERT INTO Users (UserName, Id) VALUES ('Jerry', 2);
INSERT INTO Users (UserName, Id) VALUES ('Joey', 3);
Eles estão sendo executados simultaneamente.
Por algum motivo, o segundo insert
está atrasado. Neste caso, quando o terceiro insert
está sendo executado, estou esperando um dos dois resultados abaixo:
- as
insert
falhas; - ter
insert
sucesso com um novo Id2
.
Existe algum mecanismo para conseguir isso?
Por que preciso disso?
Há um gerador de ID que gera IDs com algoritmo snowflake. Concurrents insert
são executados em multi-threads. Ao ler dados da tabela, quero fazer consultas de intervalo como esta:
select * from my_table where Id > a limit 5
select * from my_table where Id > b limit 5
select * from my_table where Id > c limit 5
...
a
, b
e c
são os últimos Id vindos do anterior select
.
| --- a --- | --- b --- | --- c --- |
O problema é que quando o segundo select
está em execução, ainda pode ser possível fazer um insert
na a
zona por causa de concurrent insert
. Se isso acontecer, não terei chance de ler os dados inseridos atrasados.
Não há como fazer isso a menos que você serialize as inserções em vez de executá-las concorrentemente. Isso pode afetar bastante seu desempenho.
Uma maneira de fazer isso é usar uma tabela para gerar
id
:Então suas inserções poderiam ser:
A atualização na
counter
tabela bloqueia a linha, e o bloqueio só é liberado quando a transação é feita. Como consequência, a ordem de inserção se torna a ordem de confirmação, e a ordem de inserção é a mesma que a ordem definida pelo contador.