以前或多或少的听说过,能用子查询的地方改用连接查询,性能有提升,如下的伪代码
select * from tab1 where col1 in (select col1 from tab2) select * from tab1 inner join tab2 on tab1.col1=tab2.col2
这种使用连接查询代替子查询的写法,据说在SQL2000中有效果,我没有测试过,这次测试一下在SQL2008R2中的性能如何?
首先看看独立子查询的逻辑读:
SET STATISTICS IO ON; USE AdventureWorks GO DBCC FREEPROCCACHE CHECKPOINT DBCC DROPCLEANBUFFERS SELECT count(*) FROM sales.SalesOrderHeader AS soh WHERE soh.SalesOrderID IN ( SELECT SalesOrderID FROM sales.salesOrderDetail AS sod WHERE OrderQty>1 AND sod.ProductID IN ( SELECT ProductID FROM Production.product AS p WHERE p.color=N'red' ) )
这段代码的逻辑读为:
(1 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'SalesOrderHeader'. Scan count 1, logical reads 45, physical reads 2, read-ahead reads 43, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'SalesOrderDetail'. Scan count 1, logical reads 1238, physical reads 35, read-ahead reads 1233, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 15, physical reads 4, read-ahead reads 20, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
再来看看使用连接查询的逻辑读:
DBCC FREEPROCCACHE CHECKPOINT DBCC DROPCLEANBUFFERS SELECT count(DISTINCT soh.salesorderid) FROM sales.salesorderheader AS soh JOIN sales.salesorderdetail AS sod ON soh.salesorderid=sod.salesorderid AND sod.orderqty>1 JOIN production.product AS p ON sod.productid=p.productid AND p.color=N'red'
这段代码的逻辑读为:
(1 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'SalesOrderHeader'. Scan count 1, logical reads 45, physical reads 2, read-ahead reads 43, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'SalesOrderDetail'. Scan count 1, logical reads 1238, physical reads 35, read-ahead reads 1233, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 15, physical reads 4, read-ahead reads 20, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
另外看看连接查询的第二种写法,把color=N’red'放入where 子句中
DBCC FREEPROCCACHE CHECKPOINT DBCC DROPCLEANBUFFERS SELECT count(DISTINCT soh.salesorderid) FROM sales.salesorderheader AS soh JOIN sales.salesorderdetail AS sod ON soh.salesorderid=sod.salesorderid AND sod.orderqty>1 JOIN production.product AS p ON sod.productid=p.productid WHERE p.color=N'red'
这段代码的逻辑读为:
(1 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'SalesOrderHeader'. Scan count 1, logical reads 45, physical reads 2, read-ahead reads 43, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'SalesOrderDetail'. Scan count 1, logical reads 1238, physical reads 34, read-ahead reads 1233, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Product'. Scan count 1, logical reads 15, physical reads 4, read-ahead reads 20, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
可以看到这三段代码的逻辑读是一样的,性能上没有任何的区别,看看从上到下三段代码的执行计划:
从上可以得到的结论:
1:SQLSERVER引擎优化器已足够聪明,知道这三种写法没有任何的区别,所以大家怎么写还是按照自己的习惯来
2:对于查询是这样,对于UPDATE/DELETE也是如此,子查询和连接查询在SQL2008中没有任何的区别!!