Luis Cazares (9/17/2012)
I came out with the same code as Jeff showed in the article, but I believe that Scott's code would be better as it is a single table scan instead of 2 or 3.And now call me crazy, but execution plans show one thing and time indicators show another on performance issues. Maybe is because I'm using temp tables instead of normal physical tables, but the statement with 3 table scans is performing faster than the other two. And the statement with 1 table scan is the slowest.
Can anyone confirm or deny this?
This is the code I used:
--insert into #product_details
--SELECT TOP 1000000
--'CUST' + CAST( (ROW_NUMBER() OVER( ORDER BY (SELECT NULL)) / 4) + 6 AS varchar(10)),
--ABS(CHECKSUM(NEWID())) % 5,
--GETDATE()
--FROM sys.all_columns ac1
-- CROSS JOIN sys.all_columns ac2
DECLARE @DATE datetime2, @dummy varchar(50)
SET @DATE = SYSDATETIME()
SELECT @dummy = CustId
FROM(
SELECT CustId
FROM #product_details
WHERE ProdId IN( 1,4)
GROUP BY CustId HAVING COUNT(DISTINCT prodid) = 2
EXCEPT
SELECT CustId
FROM #product_details
WHERE ProdId = 0) t
PRINT DATEDIFF( ns, @DATE, SYSDATETIME())
SET @DATE = SYSDATETIME()
SELECT @dummy = CustId
FROM
(SELECT CustId
FROM #product_details
WHERE ProdId = 1
AND CustId IN (SELECT DISTINCT CustId FROM #product_details WHERE ProdId = 4)
EXCEPT
SELECT CustId
FROM #product_details
WHERE ProdId = 0) AS A
PRINT DATEDIFF( ns, @DATE, SYSDATETIME())
SET @DATE = SYSDATETIME()
SELECT
@dummy = CustId
FROM #product_details
GROUP BY
CustId
HAVING
MAX(CASE WHEN ProdId = 0 THEN 1 ELSE 0 END) = 0 AND
MAX(CASE WHEN ProdId = 1 THEN 1 ELSE 0 END) = 1 AND
MAX(CASE WHEN ProdId = 4 THEN 1 ELSE 0 END) = 1
ORDER BY
CustId
PRINT DATEDIFF( ns, @DATE, SYSDATETIME())
SET @DATE = SYSDATETIME()
Timing seems that way.
I would still be leery of additional I/O vs other time, but if you are willing to scan the table 3 times to get response time, then I would say do this:
SELECT
CustId
FROM #product_details pd1
WHERE
prodid = 1 AND
EXISTS(SELECT 1 FROM #product_details pd2 WHERE pd2.custid = pd1.custid AND pd2.prodid = 4) AND
NOT EXISTS(SELECT 1 FROM #product_details pd3 WHERE pd3.custid = pd1.custid AND pd3.prodid = 0)
SQL DBA,SQL Server MVP(07, 08, 09) A socialist is someone who will give you the shirt off *someone else's* back.