Eu me pergunto por que há uma diferença no custo do plano de execução para as 2 consultas:
create table test_insert(id int not null primary key, value varchar2(10));
--1
insert into test_insert(id,value)
values (2,'111');
--2
insert into test_insert(id,value)
select 3,'111' from dual where not exists (select null from test_insert where id =3);
O custo da consulta 2 é sempre maior (quanto depende do número de linhas na tabela). No meu entendimento not exits ...
, não deve adicionar nenhuma sobrecarga - para impor a restrição de PK, o mecanismo deve verificar o índice exclusivo correspondente de qualquer maneira, portanto, a subconsulta adiciona tempo de análise extra, mas não tempo de execução ou etapa extra ao plano.
O exemplo é para Oracle, mas verifiquei o Postgres também, os resultados são semelhantes.
Por exemplo,
--1
| Id | Operation | Name | Cost |
--------------------------------------------------------
| 0 | INSERT STATEMENT | | 1 |
| 1 | LOAD TABLE CONVENTIONAL | TEST_INSERT | |
--------------------------------------------------------
--2
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | INSERT STATEMENT | | | | 3 (100)| |
| 1 | LOAD TABLE CONVENTIONAL | TEST_INSERT | | | | |
|* 2 | FILTER | | | | | |
| 3 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | SYS_C0012345 | 1 | 13 | 1 (0)| 00:00:01 |
Não sei exatamente o que você está tentando demonstrar, na parte inferior você tem um
NOT EXISTS
. Isso implica ou umindex only scan
plano PostgreSQL,
Então é claro que é mais lento. Ele está verificando o índice antes de inserir e, em seguida, a inserção de btree para a PRIMARY KEY está verificando novamente (como sempre deve).
Se você quiser rolar isso em um teste ou pule, use
ON CONFLICT DO NOTHING
Aqui está um exemplo do seu problema. Esquema de amostra,
Transações de amostra,
O que acontece no acima?
EXISTS
padrão obtêm um instantâneo. E então ele aguenta e vai dormir.READ COMMITTED ISOLATION
A primeira transação gera um erro,
Mude a ordem dessas transações e a primeira transação vê que a chave está lá e nunca tenta inserir na btree.
Espero que isso ajude você a entender o que está acontecendo.