para este caso específico, que trataré de explicar a continuación, usar una variable de tabla funciona mejor que no usar una variable de tabla.
Me gustaría saber por qué, y si es posible, deshacerme de la variable de tabla.
Esta es la consulta usando la variable de tabla:
USE [BISource_UAT]
GO
set statistics io on
SET STATISTICS TIME ON
SET NOCOUNT ON;
DECLARE @OrderStartDate DATETIME = '15-feb-2015'
DECLARE @OrderEndDate DATETIME = '28-feb-2016'
DECLARE @tmp TABLE
(
strBxOrderNo VARCHAR(20)
,sintReturnId INT
)
INSERT INTO @tmp
SELECT strBxOrderNo
,sintReturnId
FROM TABLEBACKUPS.dbo.tblBReturnHistory rh
WHERE rh.sintReturnStatusId in ( 3 )
AND rh.dtmAdded >= @OrderStartDate
AND rh.dtmAdded < @OrderEndDate
SELECT
op.lngPaymentID
,op.strBxOrderNo
,op.sintPaymentTypeID
,op.strCurrencyCode
,op.strBCCurrencyCode
,op.decPaymentAmount
,op.decBCPaymentAmount
,ap.strAccountCode
,o.sintMarketID
,o.sintOrderChannelID
,o.sintOrderTypeID
,CASE WHEN opgv.lngpaymentID IS NULL THEN NULL
-- Not a Voucher = Null
WHEN gvp.strIssuedBxOrderNo IS NULL THEN 0 ELSE 1
END AS [IsPromoVoucher] -- Is a Voucher - check type
,o.sdtmOrdCreated
FROM @tmp rh
INNER JOIN TABLEBACKUPS.dbo.tblBReturn r
ON r.sintReturnId = rh.sintReturnId
AND r.strBxOrderNo = rh.strBxOrderNo
INNER JOIN bocss2.dbo.tblBOrder o
ON o.strBxOrderNo = r.strBxOrderNo
INNER JOIN Bocss2.dbo.tblBOrderPayment op
ON op.strBxOrderNo = o.strBxOrderNo
INNER JOIN TABLEBACKUPS.dbo.tblBOrderItemReturn AS oir
ON r.sintReturnId = oir.sintReturnID
AND r.strBxOrderNo = oir.strBxOrderNo
INNER JOIN Bocss2.dbo.tblBOrderItem AS i
ON i.strBxOrderNo = oir.strBxOrderNo
AND i.sintOrderSeqNo = oir.sintOrderSeqNo
INNER JOIN TABLEBACKUPS.dbo.tblBAccountParticipant ap
ON o.lngAccountParticipantID = ap.lngParticipantID
LEFT OUTER JOIN TABLEBACKUPS.dbo.tblBOrderPaymentGiftVoucher opgv
ON op.lngPaymentID = opgv.lngPaymentID
LEFT OUTER JOIN TABLEBACKUPS.dbo.tblBGiftVoucher gv
ON opgv.strVoucherNumber = gv.strVoucherNumber
LEFT OUTER JOIN TABLEBACKUPS.dbo.tblBGiftVoucherPromotion gvp
ON gvp.strIssuedBxOrderNo = gv.strIssuedBxOrderNo
WHERE oir.decReturnFinalAmount > 0
AND o.sdtmOrdCreated >= @OrderStartDate
esto produce las siguientes estadísticas:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 78 ms, elapsed time = 86 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
Table '#BF0B2154'. Scan count 0, logical reads 1957, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBReturnHistory'. Scan count 1, logical reads 13, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 16 ms, elapsed time = 9 ms.
Table 'tblBGiftVoucherPromotion'. 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 'tblBGiftVoucher'. 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 'tblBOrderPaymentGiftVoucher'. Scan count 0, logical reads 452, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrderItem'. Scan count 0, logical reads 904, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrderPayment'. Scan count 186, logical reads 1649, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBAccountParticipant'. Scan count 0, logical reads 7112, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrder'. Scan count 3557, logical reads 14267, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrderItemReturn'. Scan count 1951, logical reads 5865, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBReturn'. Scan count 0, logical reads 3902, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#BF0B2154'. Scan count 1, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 125 ms, elapsed time = 138 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
usando showplan_text en Me gustaría mostrar el plan de consulta:
primera parte de la consulta: completar la variable de tabla
segunda parte de la consulta: usando la variable de tabla y uniendo las otras tablas:
Este es el plan XML de la consulta usando la variable de tabla.
ahora esta es la misma consulta que NO usa una variable de tabla:
USE [BISource_UAT]
GO
set statistics io on
SET STATISTICS TIME ON
SET NOCOUNT ON;
DECLARE @OrderStartDate DATETIME = '15-feb-2015'
DECLARE @OrderEndDate DATETIME = '28-feb-2016'
SELECT
op.lngPaymentID
,op.strBxOrderNo
,op.sintPaymentTypeID
,op.strCurrencyCode
,op.strBCCurrencyCode
,op.decPaymentAmount
,op.decBCPaymentAmount
,ap.strAccountCode
,o.sintMarketID
,o.sintOrderChannelID
,o.sintOrderTypeID
,CASE WHEN opgv.lngpaymentID IS NULL
THEN NULL -- Not a Voucher = Null
WHEN gvp.strIssuedBxOrderNo IS NULL
THEN 0 ELSE 1 END AS [IsPromoVoucher]
-- Is a Voucher - check type
,o.sdtmOrdCreated
FROM TABLEBACKUPS.dbo.tblBReturnHistory rh
INNER JOIN TABLEBACKUPS.dbo.tblBReturn r
ON r.sintReturnId = rh.sintReturnId
AND r.strBxOrderNo = rh.strBxOrderNo
INNER JOIN bocss2.dbo.tblBOrder o
ON o.strBxOrderNo = r.strBxOrderNo
AND o.sdtmOrdCreated >= @OrderStartDate
INNER JOIN Bocss2.dbo.tblBOrderPayment op
ON op.strBxOrderNo = o.strBxOrderNo
INNER JOIN TABLEBACKUPS.dbo.tblBOrderItemReturn AS oir
ON r.sintReturnId = oir.sintReturnID
AND r.strBxOrderNo = oir.strBxOrderNo
AND oir.decReturnFinalAmount > 0
INNER JOIN Bocss2.dbo.tblBOrderItem AS i
ON i.strBxOrderNo = oir.strBxOrderNo
AND i.sintOrderSeqNo = oir.sintOrderSeqNo
INNER JOIN TABLEBACKUPS.dbo.tblBAccountParticipant ap
ON o.lngAccountParticipantID = ap.lngParticipantID
LEFT OUTER JOIN TABLEBACKUPS.dbo.tblBOrderPaymentGiftVoucher opgv
ON op.lngPaymentID = opgv.lngPaymentID
LEFT OUTER JOIN TABLEBACKUPS.dbo.tblBGiftVoucher gv
ON opgv.strVoucherNumber = gv.strVoucherNumber
LEFT OUTER JOIN TABLEBACKUPS.dbo.tblBGiftVoucherPromotion gvp
ON gvp.strIssuedBxOrderNo = gv.strIssuedBxOrderNo
WHERE rh.sintReturnStatusId in ( 3 )
AND rh.dtmAdded >= @OrderStartDate
AND rh.dtmAdded < @OrderEndDate
Al echar un vistazo a las estadísticas, esto es lo que tenemos:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
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 'tblBGiftVoucher'. 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 'tblBAccountParticipant'. Scan count 1, logical reads 32, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBReturn'. Scan count 1, logical reads 170, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrderItemReturn'. Scan count 0, logical reads 35849, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrderPayment'. Scan count 9408, logical reads 87643, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrderItem'. Scan count 1950, logical reads 8336, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrder'. Scan count 1951, logical reads 7835, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBReturnHistory'. Scan count 1, logical reads 13, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBOrderPaymentGiftVoucher'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'tblBGiftVoucherPromotion'. Scan count 1, logical reads 27, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 625 ms, elapsed time = 612 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
Ahora, con respecto al plan de ejecución en formato de texto:
establecer los parámetros
Ahora la parte importante, ejecutar el espectáculo:
Este es el plan XML de la consulta que NO utiliza la variable de tabla.
Pero, ¿por qué al usar la variable de tabla obtuve menos lecturas, menos E / S y la ejecución (sin borrar el caché) siempre ha sido más rápida?
Puedo proporcionar cualquier script de creación de tabla, o cualquier otra cosa necesaria para una mejor comprensión de esta situación.
simplemente publique cualquier comentario aquí y le responderé.
Esta es una pregunta similar:
al ejecutar las consultas después de CHECKPOINT ; DBCC DROPCLEANBUFFERS ; los resultados fueron:
consulta con variable de tabla
consulta sin variable de tabla
fuente
Respuestas:
Los principales factores en juego aquí son:
La estimación de cardinalidad para una variable de tabla es de 1 fila (a menos que se produzca una recompilación de nivel de instrucción o el indicador de seguimiento 2453 esté activo). Esta baja estimación da como resultado un plan de muy bajo costo, que presenta una estrategia de navegación basada en bucles anidados. Este plan puede continuar siendo efectivo para recuentos de filas relativamente bajos, especialmente si los datos necesarios no necesitan ser leídos desde un almacenamiento persistente.
Con estimaciones de cardinalidad más precisas, el optimizador favorece un plan utilizando combinaciones hash y algunos escaneos. Esto parece ser más barato que una estrategia de navegación, dados los supuestos enumerados anteriormente; especialmente en relación con la memoria caché en frío y el costo relativamente bajo de una exploración secuencial en comparación con muchas búsquedas (suponiendo un patrón de E / S en gran medida aleatorio).
El plan variable de la tabla puede ser más lento que la alternativa si los datos necesarios no están en la memoria, o puede que no . El modelo de costo es exactamente eso, un modelo, los números exactos utilizados pueden no ser representativos de su hardware y configuración, y las suposiciones hechas pueden no ser válidas en las circunstancias particulares.
Todas estas advertencias se aplican especialmente a consultas de bajo costo (que son ambas) ya que los pequeños cambios de costo pueden producir formas de plan muy diferentes. De hecho, ambos planes tienen éxito en que producen resultados con rapidez y eficacia suficiente .
fuente