我想知道为什么这两个查询的执行计划成本不同:
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);
查询 2 的成本总是更高(多少取决于表中的行数)。根据我的理解not exits ...
,不应增加任何开销——为了强制执行 PK 约束,引擎无论如何都必须检查相应的唯一索引,因此子查询会增加额外的解析时间,但不会增加执行时间或计划的额外步骤。
该示例适用于 Oracle,但我也检查了 Postgres,结果相似。
例如,
--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 |
我不太确定你想展示什么,在底部你有一个
NOT EXISTS
. 这需要index only scan
PostgreSQL 计划,
所以当然慢了。它在插入之前检查索引,然后 PRIMARY KEY 的 btree 插入再次检查(因为它总是必须的)。
如果你想把它变成一个尝试或跳过,使用
ON CONFLICT DO NOTHING
这是您的问题的示例..示例架构,
样本交易,
上面发生了什么?
EXISTS
在默认READ COMMITTED ISOLATION
级别运行的测试会得到一个快照。然后它会停止并进入睡眠状态。第一个事务抛出错误,
虽然切换这些交易的顺序,但第一个交易看到密钥在那里并且从不尝试插入到 btree 中。
希望这可以帮助您了解正在发生的事情。