19

ページ番号やその他のものによって制限される結果セットを返す手順があります。出力パラメーターとして、ページ番号を除くパラメーターに従って、選択された行の合計量を返す必要があります。だから私はそのようなものを持っています:

WITH SelectedItems AS
(SELECT Id, Row1, Row2, ROW_NUMBER() OVER (ORDER BY Row1) AS Position
FROM Items
WHERE Row2 = @Row2)
SELECT Id, Row1, Row2
FROM SelectedItems
WHERE Position BETWEEN @From AND @To

次に、内部クエリの行数に OUTPUT パラメータを設定する必要があります。クエリをコピーしてカウントすることはできますが、このクエリは数千行を返す可能性があるため (将来的にはさらに増える可能性があります)、パフォーマンスの良い方法を探しています。テーブル変数について考えていましたが、それは良い考えですか? または他の提案はありますか?

具体的には、Microsoft SQL Server 2008 です。

ありがとう、ジャン

4

5 に答える 5

19

COUNT(*) を使用して、メイン クエリで合計行を別の列としてカウントできます。このような:

WITH SelectedItems AS
(SELECT Id, Row1, Row2, ROW_NUMBER() OVER (ORDER BY Row1) AS Position, 
COUNT(*) OVER () AS TotalRows
FROM Items
WHERE Row2 = @Row2)
SELECT Id, Row1, Row2
FROM SelectedItems
WHERE Position BETWEEN @From AND @To

これにより、出力パラメーターではなく結果セットにカウントが返されますが、要件に適合するはずです。それ以外の場合は、一時テーブルと組み合わせます。

DECLARE @tmp TABLE (Id int, RowNum int, TotalRows int);

WITH SelectedItems AS
(SELECT Id, Row1, Row2, ROW_NUMBER() OVER (ORDER BY Row1) AS Position, 
COUNT(*) OVER () AS TotalRows
FROM Items
WHERE Row2 = @Row2)
INSERT @tmp
SELECT Id, Row1, Row2
FROM SelectedItems
WHERE Position BETWEEN @From AND @To

SELECT TOP 1 @TotalRows = TotalRows FROM @tmp
SELECT * FROM @tmp

ページングされた結果だけに一時テーブルを使用しても、メモリはあまり使用されず (もちろんページ サイズによって異なります)、短時間しか使用しないことがわかります。一時テーブルから完全な結果セットを選択し、TotalRows を選択すると、ほんの少し時間がかかります。

これは、私のテスト (WITH の繰り返し) で実行時間が 2 倍になった、完全に別のクエリを実行するよりもはるかに高速です。

于 2009-02-24T15:46:34.070 に答える
3

別のクエリで行う必要があると思います。これら 2 つのクエリはほとんど同じに見えるかもしれませんが、クエリ オプティマイザーがそれらを処理する方法はかなり異なります。

理論的には、SQL Server は、サブクエリ内のすべての行を調べて、それを数えることさえできない場合があります。

于 2009-02-24T11:38:15.900 に答える
2

現在、コード ベースにアクセスすることはできませんが、COUNT() OVER (または同様のコマンド) を使用して、サブクエリの一部として行の総数を返すことができると思います。その後、最終的な結果セットの一部としてそれを返すことができます。それはすべての行で複製されますが、ページングを使用していて最終結果を制限する必要があるアプリケーションの私の意見では、これは小さなパフォーマンス ヒットです。

数時間以内に、正確なコードを投稿します。

編集:これは、カウントを生成するために使用した行です。最終的に、私たちの開発者は、それ自体でカウントを取得するための別のメソッドを望んでいたため、現在、同じストアド プロシージャ内の 2 つの場所で検索条件を維持しています。

COUNT(*) OVER (PARTITION BY '') AS TotalCount

それを CTE に追加すると、TotalCount を選択できます。これは、各行の列になります。

于 2009-02-24T12:03:21.907 に答える
2

完全な行数を取得するには、範囲を制限せずにクエリ全体を少なくとも 1 回実行する必要があります。とにかくこれを行うため、すべての行に冗長な count(*) 列を使用してデータ リーダーをオーバーロードするのではなく、見つかった行の合計を出力するために @@RowCount を選択する必要があります。

1. 初めて NEW クエリを実行する場合:

select YOUR_COLUMNS 
from YOUR_TABLE 
where YOUR_SEARCH_CONDITION 
order by YOUR_COLUMN_ORDERING_LIST;
select @@rowcount;

2. 最初の X 行だけを読み取る

上記のクエリは、SqlDataReader.Read() への呼び出しごとに送信される冗長な COUNT(*) 列で SqlDataReader をフラッディングすることを回避します。 初めてクエリを実行しているので、範囲を選択する代わりに、最初の X 行だけを読み取ります。 これにより、完全な結果カウント、最初の X レコード、および冗長なカウント列のない結果セットの効率的なストリーミングが実現します。

3. 結果のサブセットを取得するための SAME クエリの後続の実行

select YOUR_COLUMNS 
from (select YOUR_COLUMNS, ROW_NUMBER() 
over(order by BY YOUR_COLUMN_ORDERING_LIST) as RowNum) Results 
where Results.RowNum between @From and @To;

いずれにせよ、@@rowcount結果セットを制限せずにクエリの最初の実行でカウントにアクセスする最も直接的な方法です (とにかく最初の X 結果が必要です)、別の count() クエリを実行せずに、一時テーブルを使用せずに、冗長な count() 列を含めずに。

于 2010-05-17T19:25:23.030 に答える
1

出力変数を @@RowCount に設定できませんでしたか? これにより、最後に実行されたステートメントの影響を受けた行が取得されます。

SELECT stuff FROM mytable

SET @output = @@ROWCOUNT

これにより、必要なものが得られ、クエリを再度実行する必要はありません。

于 2009-02-25T03:13:55.370 に答える