我正在尝试在MS SQL Server上加入2个或更多表。所有表都有IsActive字段,用于确定活动记录。 (IsActive = 1表示活动记录,IsActive = 0表示已从系统中删除非活动记录或记录)
所以我有两个加入两个或更多表的条件。
在第一个查询中,我过滤了连接子句
上的IsActiveselect * from table_A a
inner join table_B b
on a.ID = b.ID and b.IsActive = 1
inner join table_C c
on b.ID = c.ID and c.IsActive = 1
where a.IsActive = 1
On第二个查询,我也可以在where子句
上过滤IsActiveselect * from table_A a
inner join table_B b
on a.ID = b.ID
inner join table_C c
on b.ID = c.ID
where a.IsActive = 1 and b.IsActive = 1
and c.IsActive = 1
注意:表A到B的关系是一对一的,但是从表A到C是一对多,并且所有表都在主键ID上有聚簇索引,ID是自动增量。
那么你认为哪一个更好? (假设每个表有大约100.000条记录(80%活动记录和20%非活动记录))
由于
答案 0 :(得分:1)
区别很简单但需要仔细观察。
考虑以下示例:
create table tbl_client as
select 1 as client_id, 'aaa' as client_name, 'Y' is_active from dual
union all
select 2, 'bbbbb', 'N' from dual
union all
select 3, 'cc', 'Y' from dual;
create table tbl_transaction as
select 1 transaction_id, 1 client_id, 123.34 amount from dual
union all
select 2, 1, 4353.45 from dual
union all
select 3, 2, 251.48 from dual;
现在,在这些表上运行后续查询:
内部加入:
在内部联接中,以下两个查询的结果没有区别:
select c.client_name, t.amount, t.is_paid
from tbl_client c
inner join tbl_transaction t
on c.client_id = t.client_id
and t.is_paid = 'Y'; -- filter on join
select c.client_name, t.amount, t.is_paid
from tbl_client c
inner join tbl_transaction t
on c.client_id = t.client_id
where t.is_paid = 'Y'; -- filter in where
他们的结果都与:
相同CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y
左外连接
这就是差异所在。
考虑以下问题:
select c.client_name, t.amount, t.is_paid
from tbl_client c
left outer join tbl_transaction t
on c.client_id = t.client_id
and t.is_paid = 'Y'; -- << filter in join
结果:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y
cc -- << Note that client cc's transaction record is not there
bbbbb -- << and this client also shows up
当您在左外连接中的where
上应用过滤器时:
select c.client_name, t.amount, t.is_paid
from tbl_client c
left outer join tbl_transaction t
on c.client_id = t.client_id
where t.is_paid = 'Y'; -- << filter in where
结果:
CLIENT_NAME AMOUNT IS_PAID
----------- ---------- -------
aaa 123.34 Y
aaa 4353.45 Y -- No row for bbbbb or cc clients, just like the inner join
<强>摘要强>
简而言之,当您在连接条件上放置过滤器时,过滤器将应用于要连接的表。例如,在左外连接部分的第一种情况下,tbl_transaction
的行没有显示给客户bbbbb
。
但是当您在where
子句中放置过滤器时,它会过滤加入所有表后检索的整个数据集(逻辑上。内部技术操作因RDBMS而异)。这就是bbbbb
和cc
的行未显示在上一个查询中的原因。
<强> Fiddle 强>
修改强>
正如@DanGuzmanSqlServerMvp在他的评论中提到的,对于您在问题中发布的示例,SQL Server查询优化器应该执行相同的计划。但是,如果查询中存在外部联接,则计划会有所不同。