SQL Server 2012で新しいLAGおよびLEAD関数を使用する利点は何ですか?
クエリをデバッグするのが簡単なだけの問題ですか、それともパフォーマンスの向上もありますか?
このタイプの機能が頻繁に必要になるため、これは私にとって重要です。近い将来、アップグレードを推奨する必要があるかどうかを知る必要があります。
クエリが簡単なだけの場合は、アップグレードの手間(およびコスト)の価値はありません。
SQL Server 2012で新しいLAGおよびLEAD関数を使用する利点は何ですか?
クエリをデバッグするのが簡単なだけの問題ですか、それともパフォーマンスの向上もありますか?
このタイプの機能が頻繁に必要になるため、これは私にとって重要です。近い将来、アップグレードを推奨する必要があるかどうかを知る必要があります。
クエリが簡単なだけの場合は、アップグレードの手間(およびコスト)の価値はありません。
実行プランの違いを示すために、DaveのSQLAuthorityブログの受賞ソリューションを使用しました。
;WITH T1
AS (SELECT row_number() OVER (ORDER BY SalesOrderDetailID) N
, s.SalesOrderID
, s.SalesOrderDetailID
FROM
TempDB.dbo.LAG s
WHERE
SalesOrderID IN (20120303, 20120515, 20120824, 20121031))
SELECT SalesOrderID
, SalesOrderDetailID AS CurrentSalesOrderDetailID
/* , CASE
WHEN N % 2 = 1 THEN
max(CASE
WHEN N % 2 = 0 THEN
SalesOrderDetailID
END) OVER (PARTITION BY (N + 1) / 2)
ELSE
max(CASE
WHEN N % 2 = 1 THEN
SalesOrderDetailID
END) OVER (PARTITION BY N / 2)
END LeadVal */
, CASE
WHEN N % 2 = 1 THEN
max(CASE
WHEN N % 2 = 0 THEN
SalesOrderDetailID
END) OVER (PARTITION BY N / 2)
ELSE
max(CASE
WHEN N % 2 = 1 THEN
SalesOrderDetailID
END) OVER (PARTITION BY (N + 1) / 2)
END PreviousSalesOrderDetailID
FROM
T1
ORDER BY
SalesOrderID
, SalesOrderDetailID;
SELECT SalesOrderID
, SalesOrderDetailID AS CurrentSalesOrderDetailID
, LAG(SalesOrderDetailID, 1, 0) OVER (ORDER BY SalesOrderID, SalesOrderDetailID) AS PreviousSalesOrderDetailID
FROM TempDB.dbo.LAG
WHERE SalesOrderID IN (20120303, 20120515, 20120824, 20121031);
Warning: Null value is eliminated by an aggregate or other SET operation.
(10204 row(s) affected)
Table 'Worktable'. Scan count 6, logical reads 81638, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LAG'. Scan count 4, logical reads 48, 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 = 297 ms, elapsed time = 332 ms.
--- versus ---
(10204 row(s) affected)
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 'LAG'. Scan count 4, logical reads 48, 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 = 78 ms, elapsed time = 113 ms.
はるかにエレガントであることに加えて、それははるかに少ないリソースを消費します。
グラフィカルな実行プランの比較は次のとおりです。
実行計画は、この特定のケースで1つの明確な勝者を示しています。Daveのページには、LEAD/LAG機能を取得するためのさまざまな方法があります。たぶんそれらのいくつかはSQLServerの内部ソリューションを打ち負かすでしょう。またはそうでないかもしれません。
MS SQL Server 2012についてはあまりコメントできませんが、PostgreSQLの観点からは、これらの関数はバージョン8.4以降で使用できます。
一般に、これらは変更を検出するのに非常に便利です(通常、時系列で、と組み合わせてORDER BY
)。通常:
WITH shifted_timeseries AS (
SELECT event_time,
value,
LAG(value) OVER (ORDER BY event_time) AS lagged_value
FROM timeseries
)
SELECT event_time AS change_time, value AS new_value
FROM shifted_timeseries
WHERE value != lagged_value;
この種のことについては、明快さだけで言えば、それだけの価値があります(それはおそらく主観的ですが)。
より複雑な操作の場合、たとえば、連続する値の期間が必要な場合、この回答はこの問題に対する非常に優れたソリューションです。このSQLFiddleによると、SQLServer2012では正常に機能しているようです。
これらの2つのブログエントリは、LEAD / LAGを使用する場合と、以下を使用せずに同じクエリを実行する場合の比較も示しています。
(実行計画を比較するのは興味深いでしょう。)