|
IF EXISTS vs COUNT(*)
Disclaimer: I’m in no way suggesting that you should replace all Exists with Count, this is just an example which worked for me.
|
|
if exists ( select * from dbo.sService ss inner join dbo.RuleUsage bru on ss.RuleUsageID = bru.RuleUsageID inner join dbo.sRule br on br.RuleID = bru.RuleID inner join dbo.sale isi on isi.SaleID=ss.SaleID inner join dbo.iSale inS on InS.SaleID = isi.SaleID and inS.SaleID=ss.SaleID where br.RuleID=@RuleID and inS.ProductID = @ProductID ) select 0 else select 1
|
|
Table 'sRule'. Scan count 1, logical reads 2, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'iSale'. Scan count 594687, logical reads 3,197,254, physical reads 2456, read-ahead reads 1837, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'sSale'. Scan count 1, logical reads 2354, physical reads 17, read-ahead reads 3624, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'RuleUsage'. Scan count 1, logical reads 2, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
v It is claimed that the optimiser applies special rules to IF EXISTS which makes this type of query optimal. v In fact for as far back as I can remember there have been examples and forum posts on which is quicker or best or optimal or……. v As usual I believe the reality is that “ It just depends “ to coin an oft used phrase.
ü What does tend to be true is that behaviour seems to change from version to version of SQL Server. ü Experience shows that single IF EXISTS seem to work fine, it’s when there is a join that performance issue occur.
The example here is a sanitised version which is why it can’t be demonstrated live, in actual fact with no data in cache on an 8 core server with a fast disk system it takes close to a minute for the original query to run , on a laptop I fear it might never finish.
The three largest tables contain 21 million, 11 million and 3 million rows; the query had effective indexes to cover the join and sarg
Here’s the deployed solution
|
|
select @count = COUNT_BIG(*) from dbo.sService ss inner join dbo.RuleUsage bru on ss.RuleUsageID = bru.RuleUsageID inner join dbo.sRule br on br.RuleID = bru.RuleID inner join dbo.sale isi on isi.SaleID=ss.SaleID inner join dbo.iSale inS on InS.SaleID = isi.SaleID and inS.SaleID=ss.SaleID where br.RuleID=@RuleID and inS.ProductID = @ProductID option (maxdop 16 ); -- if ( @count )>0 select 0 else select 1 --end
|
|
Table 'iSale'. Scan count 9, logical reads 8517, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'RuleUsage'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'sSale'. Scan count 45, logical reads 164,025, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 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 'sRule'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 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.
ü COUNT_BIG is 8 bytes vs 4bytes for count. ( Yes for some reason this query generates more than 2,147 million rows )
© www.grumpyolddba.co.uk September 2010
|