Quantcast
Channel: Transact-SQL forum
Viewing all articles
Browse latest Browse all 23857

Same query, slight alteration - very different execution times!

$
0
0

Hi everybody,

I have a stored procedure I need to optimize. I am trying different variations of the same query and two same variations that should be identical in execution plans yield very different performance: first executes in less that a second, the second variation takes a minute or more.

This is the original code:

WITH Purchases
AS (
	SELECT i.descrip
		,tr.date_time
		,CAST(0 AS MONEY) AS LoadAmount
		,CAST(0 AS MONEY) AS BonusAmount
		,tr.extension AS PurchaseAmount
		,sh.pmt_amt1 + sh.pmt_amt2 + sh.pmt_amt3 + sh.pmt_amt4 AS TotalPayments
		,ROW_NUMBER() OVER (
			PARTITION BY sh.sale_no ORDER BY CASE 
					WHEN tr.extension = 0
						THEN 1
					ELSE 2
					END
			) AS RecNo
		,tc.extension AS CardPayment
		,tr.department
		,tr.category
		,tr.item
		,tr.sale_no
		,tr.operator
		,tr.salespoint
		,ISNULL(cc.card_id, SPACE(4)) AS card_id
		,COALESCE(cc.card_type, SPACE(4)) AS card_type
		,tr.init_price
		,tr.quantity
		,tr.mastertran
		,tr.message
		,@nInvoiceNo AS Invoice_No
	FROM dbo.tr_info tic
	JOIN dbo.transact tc ON tc.trans_no = tic.trans_no
		AND tc.department = '**TRANS**'
		AND tc.message NOT IN (
			'LOAD'
			,'CASHOUT'
			)
	JOIN dbo.sale_hdr sc ON sc.sale_no = tc.sale_no
	-- Transaction detail: 
	JOIN dbo.sale_hdr sh ON sh.mastersale = sc.mastersale
	JOIN dbo.transact tr ON tr.sale_no = sh.sale_no
		AND tr.department <> '**TRANS**' -- AND tr.message NOT IN ('LOAD','CASHOUT') 
	JOIN dbo.items i ON i.department = tr.department
		AND i.category = tr.category
		AND i.item = tr.item
	LEFT OUTER JOIN dbo.cc_trans cc ON cc.sale_no = tr.sale_no -- attempt to get credit card info for the Credit card the IHC was purchased / re-loaded 
		AND DATALENGTH(cc.approval) > 0
		AND cc.card_id <> RIGHT(RTRIM(@cCardNo), 4)
	WHERE tic.info_num = CAST(@nPassNo AS CHAR(17))
		AND tic.info_type = 25
	)
	,Loads
AS (
	SELECT i.descrip
		,tr.date_time
		,tr.extension AS LoadAmount
		,COALESCE(BonusAmount, 0) AS BonusAmount
		,CAST(0 AS MONEY) AS PurchaseAmount
		,CAST(0 AS MONEY) AS CardPayment
		,tr2.department
		,tr2.category
		,tr2.item
		,tr.sale_no
		,tr.operator
		,tr.salespoint
		,ISNULL(cc.card_id, SPACE(4)) AS card_id
		,COALESCE(cc.card_type, SPACE(4)) AS card_type
		,tr.init_price
		,tr.quantity
		,tr.mastertran
		,tr.message
		,@nInvoiceNo AS invoice_no
	FROM dbo.transact tr
	LEFT JOIN (
		SELECT t.extension AS BonusAmount
			,t.mastertran
		FROM dbo.transact t
		INNER JOIN dbo.tr_info ti ON t.trans_no = ti.trans_no
			AND ti.info_type = 90
			AND ti.info_num = CAST(@nInvoiceNo AS CHAR(17))
		WHERE t.invoice_no = @nInvoiceNo
			AND t.message = 'LOAD'
		) Bonus ON tr.mastertran = Bonus.mastertran
	INNER JOIN dbo.transact tr2 ON tr.mastertran = tr2.mastertran
		AND tr2.department <> '**TRANS**'
	LEFT OUTER JOIN dbo.cc_trans cc ON cc.sale_no = tr2.sale_no -- attempt to get credit card info for the Credit card the IHC was purchased / re-loaded 
		AND DATALENGTH(cc.approval) > 0
	LEFT OUTER JOIN dbo.items i ON tr2.department = i.department
		AND tr2.category = i.category
		AND tr2.item = i.item
	WHERE tr.invoice_no = @nInvoiceNo
		AND tr.message IN (
			'LOAD'
			,'CASHOUT'
			)
		AND NOT EXISTS (
			SELECT 1
			FROM dbo.tr_info ti
			WHERE tr.trans_no = ti.trans_no
				AND ti.info_type = 90
				AND ti.info_num = CAST(@nInvoiceNo AS CHAR(17))
			)
	)
SELECT descrip
	,date_time
	,LoadAmount
	,BonusAmount
	,PurchaseAmount
	,CASE 
		WHEN RecNo = 1
			THEN CardPayment
		ELSE 0
		END AS CardPayment
	,department
	,category
	,item
	,sale_no
	,operator
	,salespoint
	,card_id
	,card_type
	,init_price
	,quantity
	,mastertran
	,MESSAGE
	,invoice_no
FROM Purchases

UNION ALL

SELECT descrip
	,date_time
	,LoadAmount
	,BonusAmount
	,PurchaseAmount
	,CardPayment
	,department
	,category
	,item
	,sale_no
	,operator
	,salespoint
	,card_id
	,card_type
	,init_price
	,quantity
	,mastertran
	,MESSAGE
	,invoice_no
FROM Loads
ORDER BY date_time;

This is first variation - executes with the same speed:

IF OBJECT_ID('TempDB..#Purchases', N'U') IS NOT NULL DROP TABLE #Purchases; IF OBJECT_ID('TempDB..#Loads', N'U') IS NOT NULL DROP TABLE #Loads; SELECT tic.trans_no INTO #Purchases FROM dbo.tr_info tic WHERE tic.info_num = @cPassNo AND tic.info_type = 25; SELECT tr.date_time ,tr.extension AS LoadAmount ,tr.sale_no ,tr.operator ,tr.salespoint ,tr.init_price ,tr.quantity ,tr.mastertran ,tr.message INTO #Loads FROM dbo.transact tr WHERE tr.invoice_no = @nInvoiceNo AND tr.message IN ( 'LOAD' ,'CASHOUT' ) AND NOT EXISTS ( SELECT 1 FROM dbo.tr_info ti WHERE tr.trans_no = ti.trans_no AND ti.info_type = 90 AND ti.info_num = CAST(@nInvoiceNo AS CHAR(17)) ); WITH Purchases AS ( SELECT i.descrip ,tr.date_time ,CAST(0 AS MONEY) AS LoadAmount ,CAST(0 AS MONEY) AS BonusAmount ,tr.extension AS PurchaseAmount ,sh.pmt_amt1 + sh.pmt_amt2 + sh.pmt_amt3 + sh.pmt_amt4 AS TotalPayments ,ROW_NUMBER() OVER ( PARTITION BY sh.sale_no ORDER BY CASE WHEN tr.extension = 0 THEN 1 ELSE 2 END ) AS RecNo ,tc.extension AS CardPayment ,tr.department ,tr.category ,tr.item ,tr.sale_no ,tr.operator ,tr.salespoint ,ISNULL(cc.card_id, SPACE(4)) AS card_id ,COALESCE(cc.card_type, SPACE(4)) AS card_type ,tr.init_price ,tr.quantity ,tr.mastertran ,tr.message ,@nInvoiceNo AS Invoice_No FROM #Purchases tic INNER JOIN dbo.transact tc ON tic.trans_no = tc.trans_no

AND tc.department = '**TRANS**' AND tc.message NOT IN ( 'LOAD','CASHOUT')

JOIN dbo.sale_hdr sc ON sc.sale_no = tc.sale_no -- Transaction detail: JOIN dbo.sale_hdr sh ON sh.mastersale = sc.mastersale JOIN dbo.transact tr ON tr.sale_no = sh.sale_no AND tr.department <> '**TRANS**' -- AND tr.message NOT IN ('LOAD','CASHOUT') JOIN dbo.items i ON i.department = tr.department AND i.category = tr.category AND i.item = tr.item LEFT OUTER JOIN dbo.cc_trans cc ON cc.sale_no = tr.sale_no -- attempt to get credit card info for the Credit card the IHC was purchased / re-loaded AND DATALENGTH(cc.approval) > 0 AND cc.card_id <> RIGHT(RTRIM(@cCardNo), 4) ) ,Loads AS ( SELECT i.descrip ,tr.date_time ,tr.LoadAmount ,COALESCE(BonusAmount, 0) AS BonusAmount ,CAST(0 AS MONEY) AS PurchaseAmount ,CAST(0 AS MONEY) AS CardPayment ,tr2.department ,tr2.category ,tr2.item ,tr.sale_no ,tr.operator ,tr.salespoint ,ISNULL(cc.card_id, SPACE(4)) AS card_id ,COALESCE(cc.card_type, SPACE(4)) AS card_type ,tr.init_price ,tr.quantity ,tr.mastertran ,tr.message ,@nInvoiceNo AS invoice_no FROM #Loads tr LEFT JOIN ( SELECT t.extension AS BonusAmount ,t.mastertran FROM dbo.transact t INNER JOIN dbo.tr_info ti ON t.trans_no = ti.trans_no AND ti.info_type = 90 AND ti.info_num = CAST(@nInvoiceNo AS CHAR(17)) WHERE t.invoice_no = @nInvoiceNo AND t.message = 'LOAD' ) Bonus ON tr.mastertran = Bonus.mastertran INNER JOIN dbo.transact tr2 ON tr.mastertran = tr2.mastertran AND tr2.department <> '**TRANS**' LEFT OUTER JOIN dbo.cc_trans cc ON cc.sale_no = tr2.sale_no -- attempt to get credit card info for the Credit card the IHC was purchased / re-loaded AND DATALENGTH(cc.approval) > 0 LEFT OUTER JOIN dbo.items i ON tr2.department = i.department AND tr2.category = i.category AND tr2.item = i.item ) SELECT descrip ,date_time ,LoadAmount ,BonusAmount ,PurchaseAmount ,CASE WHEN RecNo = 1 THEN CardPayment ELSE 0 END AS CardPayment ,department ,category ,item ,sale_no ,operator ,salespoint ,card_id ,card_type ,init_price ,quantity ,mastertran ,MESSAGE ,invoice_no FROM Purchases UNION ALL SELECT descrip ,date_time ,LoadAmount ,BonusAmount ,PurchaseAmount ,CardPayment ,department ,category ,item ,sale_no ,operator ,salespoint ,card_id ,card_type ,init_price ,quantity ,mastertran ,MESSAGE ,invoice_no FROM Loads ORDER BY date_time;


And finally, this variation takes very long to execute:

IF OBJECT_ID('TempDB..#Purchases', N'U') IS NOT NULL DROP TABLE #Purchases; IF OBJECT_ID('TempDB..#Loads', N'U') IS NOT NULL DROP TABLE #Loads; SELECT tic.trans_no INTO #Purchases FROM dbo.tr_info tic WHERE tic.info_num = @cPassNo AND tic.info_type = 25; SELECT tr.date_time ,tr.extension AS LoadAmount ,tr.sale_no ,tr.operator ,tr.salespoint ,tr.init_price ,tr.quantity ,tr.mastertran ,tr.message INTO #Loads FROM dbo.transact tr WHERE tr.invoice_no = @nInvoiceNo AND tr.message IN ( 'LOAD' ,'CASHOUT' ) AND NOT EXISTS ( SELECT 1 FROM dbo.tr_info ti WHERE tr.trans_no = ti.trans_no AND ti.info_type = 90 AND ti.info_num = CAST(@nInvoiceNo AS CHAR(17)) ); WITH Purchases AS ( SELECT i.descrip ,tr.date_time ,CAST(0 AS MONEY) AS LoadAmount ,CAST(0 AS MONEY) AS BonusAmount ,tr.extension AS PurchaseAmount ,sh.pmt_amt1 + sh.pmt_amt2 + sh.pmt_amt3 + sh.pmt_amt4 AS TotalPayments ,ROW_NUMBER() OVER ( PARTITION BY sh.sale_no ORDER BY CASE WHEN tr.extension = 0 THEN 1 ELSE 2 END ) AS RecNo ,tc.extension AS CardPayment ,tr.department ,tr.category ,tr.item ,tr.sale_no ,tr.operator ,tr.salespoint ,ISNULL(cc.card_id, SPACE(4)) AS card_id ,COALESCE(cc.card_type, SPACE(4)) AS card_type ,tr.init_price ,tr.quantity ,tr.mastertran ,tr.message ,@nInvoiceNo AS Invoice_No FROM dbo.transact tc JOIN dbo.sale_hdr sc ON sc.sale_no = tc.sale_no -- Transaction detail: JOIN dbo.sale_hdr sh ON sh.mastersale = sc.mastersale JOIN dbo.transact tr ON tr.sale_no = sh.sale_no AND tr.department <> '**TRANS**' -- AND tr.message NOT IN ('LOAD','CASHOUT') JOIN dbo.items i ON i.department = tr.department AND i.category = tr.category AND i.item = tr.item LEFT OUTER JOIN dbo.cc_trans cc ON cc.sale_no = tr.sale_no -- attempt to get credit card info for the Credit card the IHC was purchased / re-loaded AND DATALENGTH(cc.approval) > 0 AND cc.card_id <> RIGHT(RTRIM(@cCardNo), 4)

WHERE tc.trans_no IN (select trans_no FROM #Purchases)

		AND tc.department = '**TRANS**'
		AND tc.message NOT IN (
			'LOAD'
			,'CASHOUT'
			)	
	)
	,Loads
AS (
	SELECT i.descrip
		,tr.date_time
		,tr.LoadAmount
		,COALESCE(BonusAmount, 0) AS BonusAmount
		,CAST(0 AS MONEY) AS PurchaseAmount
		,CAST(0 AS MONEY) AS CardPayment
		,tr2.department
		,tr2.category
		,tr2.item
		,tr.sale_no
		,tr.operator
		,tr.salespoint
		,ISNULL(cc.card_id, SPACE(4)) AS card_id
		,COALESCE(cc.card_type, SPACE(4)) AS card_type
		,tr.init_price
		,tr.quantity
		,tr.mastertran
		,tr.message
		,@nInvoiceNo AS invoice_no
	FROM #Loads tr
	LEFT JOIN (
		SELECT t.extension AS BonusAmount
			,t.mastertran
		FROM dbo.transact t
		INNER JOIN dbo.tr_info ti ON t.trans_no = ti.trans_no
			AND ti.info_type = 90
			AND ti.info_num = CAST(@nInvoiceNo AS CHAR(17))
		WHERE t.invoice_no = @nInvoiceNo
			AND t.message = 'LOAD'
		) Bonus ON tr.mastertran = Bonus.mastertran
	INNER JOIN dbo.transact tr2 ON tr.mastertran = tr2.mastertran
		AND tr2.department <> '**TRANS**'
	LEFT OUTER JOIN dbo.cc_trans cc ON cc.sale_no = tr2.sale_no -- attempt to get credit card info for the Credit card the IHC was purchased / re-loaded 
		AND DATALENGTH(cc.approval) > 0
	LEFT OUTER JOIN dbo.items i ON tr2.department = i.department
		AND tr2.category = i.category
		AND tr2.item = i.item
	)
SELECT descrip
	,date_time
	,LoadAmount
	,BonusAmount
	,PurchaseAmount
	,CASE 
		WHEN RecNo = 1
			THEN CardPayment
		ELSE 0
		END AS CardPayment
	,department
	,category
	,item
	,sale_no
	,operator
	,salespoint
	,card_id
	,card_type
	,init_price
	,quantity
	,mastertran
	,MESSAGE
	,invoice_no
FROM Purchases

UNION ALL

SELECT descrip
	,date_time
	,LoadAmount
	,BonusAmount
	,PurchaseAmount
	,CardPayment
	,department
	,category
	,item
	,sale_no
	,operator
	,salespoint
	,card_id
	,card_type
	,init_price
	,quantity
	,mastertran
	,MESSAGE
	,invoice_no
FROM Loads
ORDER BY date_time;
So, why would moving conditions from JOIN into WHERE make the query execute such a long time?


For every expert, there is an equal and opposite expert. - Becker's Law


My blog


My TechNet articles


Viewing all articles
Browse latest Browse all 23857

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>