TLDR; #1 最适合小型 OLTP 查询,#2 最适合大型数据仓库查询。
如果相关列被索引,并且查询只处理一小部分数据,那么使用 OR 条件连接会更快。但是如果列没有被索引,或者如果查询处理了很大比例的数据,那么连接列的速度会更快。
性能比较归结为经典的数据库性能选择 - 索引读取和嵌套循环连接对一小部分行更好,而全表扫描和哈希连接对大部分行更好。
OR 条件是 sargable - 它们是简单的比较条件,可以通过遍历一个或多个索引中的有序数据来快速查找。但是,OR 条件不能用于哈希连接 - Oracle 哈希连接一次只能比较两个值。
连接的列不可搜索 - 组合值不存储在索引中,因此 Oracle 无法遍历索引来查找相关值。但是,连接的列只需要一次比较,因此可以在哈希反连接中使用。
下面的测试用例处理了所有数据,并显示连接版本比 OR 版本运行得更快。如果删除索引,OR 版本的性能会更差。
--Create tables, insert 1M sample rows, created indexes, and gather optimizer statistics.
create table customer_source(cst_id number, name varchar2(100), gender varchar2(1));
create table customer_target(cst_id number, name varchar2(100), gender varchar2(1));
insert into customer_source select level, rpad(level, 10, 'A'), 'F' from dual connect by level <= 1000000;
insert into customer_target select level, rpad(level, 10, 'A'), 'F' from dual connect by level <= 1000000;
create index customer_source_idx1 on customer_source(cst_id);
create index customer_source_idx2 on customer_source(name);
create index customer_source_idx3 on customer_source(gender);
create index customer_target_idx1 on customer_target(cst_id);
create index customer_target_idx2 on customer_target(name);
create index customer_target_idx3 on customer_target(gender);
begin
dbms_stats.gather_table_stats(user, 'customer_source');
dbms_stats.gather_table_stats(user, 'customer_target');
end;
/
--#1: OR version.
--The explain plan shows a "FILTER" operation that re-reads an index repeatedly.
explain plan for
select * from Customer_source s
where not exists
(Select 1 from Customer_target t
where s.CST_ID = t.CST_ID and ( s.NAME <> t.NAME
or s.GENDER <> t.GENDER)
);
select * from table(dbms_xplan.display);
--#2: Concatenation version.
--The explain plan shows a "HASH JOIN ANTI" operation.
explain plan for
select * from Customer_source s
where not exists (Select 1 from Customer_target t
where s.CST_ID = t.CST_ID and ( s.NAME || s.GENDER <> t.NAME || t.GENDER)
);
select * from table(dbms_xplan.display);
通常,“最佳外观”查询是运行最快的查询。连接值是丑陋的,正如其他人指出的那样,如果您的列可以为空,甚至可能无法正常工作。但是在数据仓库中,为了性能,编写奇怪的条件来启用哈希连接的情况并不少见。虽然您始终可以自己对查询进行基准测试,但最好了解这些概念,这样您就知道为什么要编写奇怪的查询。