2015 年 12 月 17 日 - 更新
この質問をしてからしばらく経ちましたが、実際には答えが得られなかったので、チームが最終的に使用したソリューションを投稿すると思いました.
最初は、動的 SQL オプションを使用してスマートな並べ替えを取得することから始めました。機能的ですが、これは本当に汚いと感じました。最終的に次の実装にたどり着きました。
--Params
DECLARE
@pageSize INT
, @pageIndex INT
, @sortBy varchar(30)
, @sortDirection varchar(4);
SET @pageIndex = 1;
SET @pageSize = 10;
SET @sortBy = 'PolicyCode';
SET @sortDirection = 'ASC';
--Vars
DECLARE @start INT,
@end INT;
--Page 1-n
SET @pageIndex = 1;
SET @pageSize = 10;
SET @start = (@pageSize * @pageIndex) - (@pageSize - 1);
SET @end = (@pageSize * @pageIndex);
;WITH PolicyCTE AS (
SELECT p.PolicyId, p.PolicyTypeId, p.PolicyCode, p.PolicyDesc, p.EffectiveDate, p.ExpirationDate
FROM Policy p INNER JOIN PolicyOrg po ON p.PolicyId = po.PolicyId
)
, PagedResultsCTE AS (
SELECT
[PolicyId]
, [PolicyTypeId]
, [PolicyCode]
, [PolicyDesc]
, [EffectiveDate]
, [ExpirationDate]
, CASE
WHEN @sortBy = 'PolicyTypeId' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyTypeId] ASC)
WHEN @sortBy = 'PolicyTypeId' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyTypeId] DESC)
WHEN @sortBy = 'PolicyCode' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyCode])
WHEN @sortBy = 'PolicyCode' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyCode] DESC)
WHEN @sortBy = 'PolicyDesc' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyDesc])
WHEN @sortBy = 'PolicyDesc' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [PolicyDesc] DESC)
WHEN @sortBy = 'EffectiveDate' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [EffectiveDate])
WHEN @sortBy = 'EffectiveDate' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [EffectiveDate] DESC)
WHEN @sortBy = 'ExpirationDate' AND @sortDirection = 'ASC' THEN ROW_NUMBER() OVER (ORDER BY [ExpirationDate])
WHEN @sortBy = 'ExpirationDate' AND @sortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY [ExpirationDate] DESC)
END AS RowNumber
FROM PolicyCTE
)
SELECT PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
FROM PagedResultsCTE
WHERE RowNumber BETWEEN @start AND @end
ORDER BY RowNumber
GO
CASE ステートメントと別の CTE を組み合わせることで、渡されたソート基準でソートし、正しい ROWNUMBER() 値を取得することもできます。次に、最後の select ステートメントで、単純に行番号列で並べ替えることができます。
誰かがこのソリューションに参加したい場合に備えて、今のところ回答済みの質問をマークすることは避けます. フィードバックは大歓迎です。
元の投稿
たぶん、DBAの知識がもう少しある人が、これに光を当てることができます。基本的な前提: ストアド プロシージャ内で最適化されたクエリを使用してページ分割されたデータを取得し、ページの読み込みパフォーマンスを向上させます (レコード 1 ~ 10、11 ~ 20 などを取得します)。テーブルには数千のレコードがあります。
私は SQL Server 2008 R2 を使用しており、ストアド プロシージャで使用する次の T-SQL を思い付きました。
--Params
DECLARE @pageSize INT,
@pageIndex INT;
SET @pageIndex = 1;
SET @pageSize = 10;
--Vars
DECLARE @start INT,
@end INT
--Page 1-n
SET @pageIndex = 1;
SET @pageSize = 10;
SET @start = (@pageSize * @pageIndex) - (@pageSize - 1);
SET @end = (@pageSize * @pageIndex)
;WITH PolicyCTE AS
(
SELECT ROW_NUMBER() OVER (ORDER BY p.PolicyCode) AS RowNumber,
p.PolicyId, p.PolicyTypeId, p.PolicyCode, p.PolicyDesc, p.EffectiveDate, p.ExpirationDate
FROM Policy p INNER JOIN PolicyOrg po ON p.PolicyId = po.PolicyId
)
SELECT PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
FROM PolicyCTE
WHERE RowNumber BETWEEN @start AND @end
ORDER BY PolicyCode
GO
これを行うためのベスト プラクティスを探していたところ、古いMSDN のパターンとプラクティスの記事「How To: Page Records in .NET Applications」に出くわしました(SQL 2000 に適用され、この記事は古くなっていると述べられています)。ユーザー固有のレコードセクションを参照すると、同等の T-SQL は次のようになります。
DECLARE
@pageIndex int,
@pageSize int,
@sortBy nvarchar(30)
SET @pageIndex = 0;
SET @pageSize = 10;
SET @sortBy = 'PolicyCode';
DECLARE @rowsToRetrieve int,
@sortDirFlipped nvarchar(4);
IF @pageIndex < 1 SET @pageIndex = 1;
IF @pageSize < 1 SET @pageSize = 10;
SET @rowsToRetrieve = @pageIndex * @pageSize
DECLARE @sqlString nvarchar(1000);
SET @sqlString = N'
SELECT PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
FROM (
SELECT TOP ' + CAST(@pageSize AS VARCHAR(10)) + ' PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
FROM (
SELECT TOP ' + CAST(@rowsToRetrieve AS VARCHAR(10)) + ' PolicyId, PolicyTypeId, PolicyCode, PolicyDesc, EffectiveDate, ExpirationDate
FROM (
SELECT TOP ' + CAST(@rowsToRetrieve AS VARCHAR(10)) + ' p.PolicyId, p.PolicyTypeId, p.PolicyCode, p.PolicyDesc, p.EffectiveDate, p.ExpirationDate
FROM Policy p INNER JOIN PolicyOrg po ON p.PolicyId = po.PolicyId
ORDER BY p.' + @sortBy + '
) AS T2
ORDER BY ' + @sortBy + ' DESC
) AS T3
) AS T4
ORDER BY ' + @sortBy + ' ASC';
EXEC(@sqlString)
GO
これらの両方を実行計画とクライアント統計をオンにして実行しましたが、MSDN バージョンの方がパフォーマンスが優れているように思えます (これらの結果を分析する専門家ではないことは間違いありません)。私が収集できる理由の 1 つは、MSDN バージョンのレコード セットが小さいことです。ただし、MSDN バージョンが動的クエリを使用しているという事実は、私は本当に嫌いです。私の理解では、それらは SQL インジェクション攻撃に対してより脆弱です。
私が見つけたほとんどの例は、最初のサンプルの形式を好みます。すでにリストされているものに加えて、最初の形式が2番目の形式よりも優れている理由を、誰かが私とサイトに説明するのを手伝ってもらえますか?