对于可为空的连接列,进行外连接或内连接到“空”行是否更好?

时间:2013-06-03 16:14:30

标签: sql sql-server join null

对于SQL查询性能,处理空列的最佳方法是什么?

假设我有一些数据对象Person和Employer。一个人可以引用一个雇主,但他们也可以失业,并通过一个空引用来表示。

DB性能对可空的EmployerId字段的左外连接更好,或者对“null”雇主进行内连接,然后在数据检索代码中将那个“null”雇主变成实际的空值?

(我知道这是一个简单的例子,但假设我有几万行外连接开始显着影响性能)

可以为空的列上的外部联接

表人(PersonId,Name,EmployerId)(EmployerId可以为空)

(1, 'John Doe', 1)  
(2, 'Joe Smith', NULL)  
(3, 'Jane Doe', 2)  

表雇主(EmployerId,姓名)

(1, 'Microsoft')  
(2, 'google')  

QUERY

SELECT * FROM Person LEFT OUTER JOIN Employers ON Person.EmployerId = Employers.EmployerId

(1, 'John Doe', 1, 'Microsoft')  
(2, 'Joe Smith', NULL, NULL)  
(3, 'Jane Doe', 2, 'google')  

除了DB读取之外,代码不必执行任何操作。

“null”行的内部联接

TABLE Person(PersonId,Name,EmployerId)(EmployerId不可为空)

(1, 'John Doe', 1)  
(2, 'Joe Smith', 0)  
(3, 'Jane Doe', 2)  

表雇主(EmployerId,姓名)

(0, '{NULL}')  
(1, 'Microsoft')  
(2, 'google')  

QUERY

SELECT * FROM Person INNER JOIN Employers ON Person.EmployerId = Employers.EmployerId

(1, 'John Doe', 1, 'Microsoft')  
(2, 'Joe Smith', 0, '{NULL}')  
(3, 'Jane Doe', 2, 'google') 

代码必须执行数据库读取,然后检测“{NULL}”并转换为空引用。

1 个答案:

答案 0 :(得分:3)

第二个版本对我来说很奇怪。 NULL更像是“缺少值”,而不是“具有NULL作为索引的相应记录”。如果您打算使用第二个版本,请使用除NULL之外的其他值。

通常,当数据库引擎支持外连接时,该算法与内连接算法非常相似。如果数据库支持嵌套循环内部联接,或索引查找内部联接,或基于散列的内部联接或marge-sort内部联接,则它支持外部联接的相同算法。由于外连接的结果集更大,性能差异更大。

顺便说一下,在你现在修改的第二个例子中,效果与内连接相同。查询是:

SELECT *
FROM Person INNER JOIN
     Employers
     ON Person.EmployerId = Employers.EmployerId

join中的一个或两个EmployerIdNULL时,NULL条件失败。除is null外,NULL未通过所有比较。因此,第二个示例不会获取带有on的雇主记录。

您可以更改 on (Person.EmployerId = Employers.EmployerId) or (Person.EmployerId is NULL and Employers.EmployerId is null) on coalesce(Person.EmployerId, -1) = coalesce(Emlpoyers.EmployerId, -1) 条件以解决此问题。这有两种方式:

or

然后在两种情况下连接不再相同。并且,这些连接可能与第一种情况完全不同。特别是,列上的{{1}}条件和函数会阻止使用索引进行连接。