EDIT :-
With PK on the Id column following is produced both for EXISTS and COUNT(*) > 0
Table 'TableWithHugeData'. Scan count 0, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
IF OBJECT_ID('TableWithHugeData') IS NOT NULL
BEGIN
DROP TABLE TableWithHugeData
END
CREATE TABLE TableWithHugeData
(
ID UNIQUEIDENTIFIER,
Name varchar(max)
)
DECLARE @Counter INT
SELECT @Counter = 0
WHILE (@Counter < 50000)
BEGIN
INSERT INTO TableWithHugeData
VALUES (NewId(),'Ashish ' + Convert(varchar(5000),@Counter))
SELECT @Counter = @Counter +1
END
EXISTS
DBCC FreeProcCache
DBCC DROPCLEANBUFFERS
SET STATISTICS IO ON
DECLARE @Id UNIQUEIDENTIFIER
SELECT @Id = '28BD1F4C-7D89-4731-9D2C-21ECB20500F8'
IF EXISTS (SELECT * FROM TableWithHugeData WHERE Id = @Id)
BEGIN
SELECT CONVERT(BIT, 1)
END
ELSE
BEGIN
SELECT CONVERT(BIT, 0)
END
IO statistics for EXISTS :-
Table ‘TableWithHugeData’. Scan count 1, logical reads 6, physical reads 1, read-ahead reads 270, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
COUNT(*) >0
DBCC FreeProcCache
DBCC DROPCLEANBUFFERS
DECLARE @Id UNIQUEIDENTIFIER
SELECT @Id = '28BD1F4C-7D89-4731-9D2C-21ECB20500F8'
IF (SELECT COUNT(*) FROM TableWithHugeData WHERE Id = @Id)>0
BEGIN
SELECT CONVERT(BIT, 1)
END
ELSE
BEGIN
SELECT CONVERT(BIT, 0)
END
*IO Statistics For Count() >0 ** :-
Table ‘TableWithHugeData’. Scan count 1, logical reads 6, physical reads 1, read-ahead reads 270, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
As you see, the IO statistics for EXISTS and COUNT(*)>0 are same. I thought EXISTS would be faster and would perform less reads. Am I missing something here? Would defining a Primary key would make any difference?
SQL Serverreads data block-wise.If the record you are looking for happens to be in the last block (or not found at all) then the
EXISTSwould still have to scan all blocks.Yes.
With the
PRIMARY KEY,EXISTSandCOUNT(*)would always be the same (single index seek).Without one,
EXISTSwould stop on first match whileCOUNT(*)would continue to the end of the table.Update:
Sorry, I was wrong earlier.
It seems that
SQL ServeroptimizesCOUNT(*) > 0toEXISTS, so yes, the statistics would be the same.And a little bit different query:
The second query needs to know exact value of
COUNT(*)so it reads all blocks (266logical reads vs.1forEXISTS / COUNT(*) > 0).