ページSQL検索ストアドプロシージャのカウントを取得する
-
06-07-2019 - |
質問
SQL Server 2005を使用してページ検索のストアドプロシージャを作成しました。多くのパラメーターを取り、検索条件はやや複雑です。
フロントエンドアーキテクチャのため、実際に結果を返すことなく 返される結果の数を返すことができる必要があります。フロントエンドは、実際の結果を取得するためにストアドプロシージャをもう一度呼び出します。
一方では、カウントを処理するためと実際のデータを処理するための2つのストアドプロシージャを作成できますが、少なくとも2つの異なる場所で検索ロジックを維持する必要があります。または、ストアドプロシージャを記述して、ビットパラメータを取得し、それに基づいてデータまたはカウントのみを返すようにすることもできます。一時テーブルにデータを入力し、それがカウントである場合はその中からカウントするだけで、そうでない場合は選択します。ここでの問題は、カウントプロセスを最適化できるため、余分なオーバーヘッドが多くなることです(不要な列を取得する必要があるなど)。また、ストアドプロシージャでこの種のロジックを使用すると、2つの使用法を行き来する際にクエリプランが不適切になる可能性があります。
システム内のデータ量はそれほど多くありません(より大きなテーブルであっても数百万行のみ)。ただし、多くの同時ユーザーが存在する場合があります。
これらのアプローチに対する人々の考えは何ですか?誰も私が考えていない方法でこの問題を以前に解決しましたか?
それらは、 CANNOT 単一のコールから結果を取得し、同時にカウントします。
ありがとう!
解決
個人的には2つのクエリアプローチを使用します。はい、検索ロジックを2か所で維持する必要がありますが、パフォーマンスの最適化の利点と、コードの全体的なクリーンさが最終的に成果を上げることがわかりました。
単一のプロシージャに渡されたフラグを使用することは解決策の可能性がありますが、特に複雑な検索ロジックの場合、メンテナンスが非常に難しいことがわかりました。
一時テーブルなどを使用するルート。必要以上のオーバーヘッドを追加するだけです。
したがって、なぜ2つのクエリメソッドを使用したのでしょうか。私がオンラインで見つけたものはすべて、このアプローチも推奨しています。
他のヒント
これは通常の問題ではありません。通常、ページを取得すると同時に合計数を求めます。
とはいえ、2つの異なる手順を使用します。その理由は、表面的には互いに類似している2つの非常に異なるアクションがあるためです。
これを考慮したと確信しています:データがCOUNTを変更し、その後の実際のページングが異なる場合(行が追加/削除された場合)
一致する行のPKを返すユーザー定義関数があり、比較的簡単に実行できます
SELECT COUNT(*) FROM dbo.MyQueryFunction(@Param1, @Param2)
カウントを取得し、
SELECT Col1, Col2, ... FROM dbo.MyQueryFunction(@Param1, @Param2) AS FN JOIN dbo.MyTable AS T ON T.ID = FN.ID ... more JOINs ...
データを取得します。
次のページングでこれがRow_Numberにどの程度適切に対応しているかはわかりませんが、実際の「クエリロジック」は維持されます。 MyQueryFunctionに含まれています-取得する列のすべてのJOINは、SprocとFunctionで複製されます。
このスレッドが他の何かを調査しているのを発見し、1つのクエリで結果セットとレコードカウントを返すことが可能であることに言及したいと思いました。値を伝えるために必要なのは「出力」パラメータだけです。以下はOracleの例のコピー/貼り付けですが、この手法はSQL Serverでも非常によく似ています(SQL Serverのatmにアクセスできません)。
SQL Serverの大きな利点は、row_number()とrownumを使用する必要がある場合があることです。
procedure get_sample_results (
startrow in number default 1,
numberofrows in number default 10,
whereclause in varchar2,
matchingrows out number,
rc out sys_refcursor
)
is
stmnt varchar2(5000);
endrow number;
begin
stmnt := stmnt || 'select * from table t where 1=1';
if whereclause is not null then
stmnt := stmnt || ' and ' || whereclause;
end if;
execute immediate 'select count(*) from (' || stmnt || ')' into matchingrows;
stmnt := 'select * from (' || stmnt || ') where rownum between :1 and :2';
-- must subtract one to compenstate for the inclusive between clause
endrow := startrow + numberofrows - 1;
open rc for stmnt using startrow, endrow;
end get_sample_results;
これは古い質問(既にマークされている)を知っていますが、レコードセット(結果)を返すことができ、出力(または複数の出力)値を持つことができます。 。
これは私が声に出して考えていることです(そして、それは私の就寝時間を過ぎています...)
CREATE PROCEDURE WhatEver
(
@SomeParam1 NVARCHAR(200),
....
@SomeParam_X INT,
@NumberOfResults INTEGER OUTPUT
)
BEGIN
SET NOCOUNT ON
-- Do your search stuff.
-- ....
SELECT Whatever
FROM WhatWhat
...
-- Ok, the results/recordset has been sent prepared.
-- Now the rowcount
SET @NumberOfResults = @@ROWCOUNT
END
HTH。