何千もの行を返す複雑なストアド プロシージャがあり、完了までに長い時間がかかります。
クエリを実行してデータをフェッチする前に、返される行数を調べる方法はありますか?
これは、Visual Studio 2005、Winforms アプリケーション、および SQL Server 2005 を使用しています。
何千もの行を返す複雑なストアド プロシージャがあり、完了までに長い時間がかかります。
クエリを実行してデータをフェッチする前に、返される行数を調べる方法はありますか?
これは、Visual Studio 2005、Winforms アプリケーション、および SQL Server 2005 を使用しています。
ストアド プロシージャが完了するまでに長い時間がかかるとおっしゃいました。データベースから行を選択するプロセス、または呼び出し元に行を返すプロセスに時間の大半が費やされていますか?
後者の場合は、実際の行の代わりにカウントを取得するだけの SP のミラー バージョンを作成できます。前者の場合は、適切な行を見つける作業が遅いため、実際にできることはそれほど多くありません。
Tony Andrewsが彼の回答で言ったことを続けると、クエリへの呼び出しの推定クエリプランを次のように取得できます。
SET showplan_text OFF
GO
SET showplan_all on
GO
--Replace with call you your stored procedure
select * from MyTable
GO
SET showplan_all ofF
GO
これにより、クエリの推定行数を取得できる1つまたは複数のテーブルが返されます。
最初に行をカウントするストアド プロシージャを作成します。
SELECT COUNT(*) FROM テーブル
これを計算できるアプリのビジネス ロジックの側面がない限り、いいえ。データベースは、行の行を把握するためにすべての where & join ロジックを実行する必要があります。これは、SP で費やされる時間の大部分です。
プロシージャを実行しないと、プロシージャの行数を取得できません。
同じパラメーターを受け入れる別のプロシージャを作成できます。その目的は、他のプロシージャが返す行数を通知することです。ただし、この手順で必要な手順は通常、メイン手順の手順と非常に似ているため、メイン手順を実行するのとほぼ同じ時間がかかります。
行数を取得するには、別のバージョンのストアド プロシージャを作成する必要があります。フィルタリングされていないテーブルの結合を排除したり、順序付けを削除したりできるため、これはおそらくはるかに高速です。たとえば、ストアドプロシージャが次のようなSQLを実行した場合:
select firstname, lastname, email, orderdate from
customer inner join productorder on customer.customerid=productorder.productorderid
where orderdate>@orderdate order by lastname, firstname;
カウントバージョンは次のようになります。
select count(*) from productorder where orderdate>@orderdate;
一般的ではありません。
ストアド プロシージャの操作に関する知識を通じて、推定値または正確な数を取得できる場合があります (たとえば、クエリの「コア」テーブルまたは「ベース」テーブルをすばやく計算できる場合)。時間を増加させる複雑な結合および/または集計)。
ただし、最初にカウント SP を呼び出してからデータ SP を呼び出すか、複数の結果セット SP を使用して調べることができます。
実際のデータを取得するのと同じくらい行数を取得するのに時間がかかる可能性があるため、ほとんどの場合、カウントを実行することはお勧めしません。
いくつかの可能性:
1) SQL Server は、クエリ オプティマイザの結果を何らかの方法で公開していますか? つまり、クエリを解析して行数の見積もりを取得できますか? (私は SQL Server を知りません)。
2) おそらく、ユーザーが提供する基準に基づいて、独自の見積もりを実行できます。たとえば、ユーザーが顧客の姓フィールドに「S%」と入力して注文を照会した場合、それが顧客レコードの 7% (たとえば) に一致すると判断でき、クエリが注文レコードの約 7% を返す可能性があると推測できます。
問題の解決策は、結果セットを次のように制限するようにストアド プロシージャを書き直すことです。
SELECT TOP 1000 * FROM tblWHATEVER
SQL Server、または
SELECT * FROM tblWHATEVER WHERE ROWNUM <= 1000
オラクルで。または、各呼び出しの結果セットが許容できるほど小さくなるように、ページング ソリューションを実装します。
返された結果セットの論理的な (意味のある) 主キーを判断するには、返されたデータ セットを分析する必要があります。一般に、サーバーは各テーブルの各行のすべての列のデータから結果セットを構築するのではなく、単に行をカウントしているため、完全な手順よりもはるかに高速になります...一般的には、これを行うには、ディスクから実際のテーブル行を読み取る必要があります。単にインデックスノードをカウントする必要があるかもしれません...
次に、それらのキー列を生成するために必要なテーブルのみを含む別の SQL ステートメントを記述し (これがメインの SQL クエリのテーブルのサブセットであることを願っています)、同じフィルター述語値を持つ同じ where 句を記述します...
次に、@CountsOnly という別の Optional パラメータを Stored Proc に追加します。デフォルトは false (0) です。
Alter Procedure <storedProcName>
@param1 Type,
-- Other current params
@CountsOnly TinyInt = 0
As
Set NoCount On
If @CountsOnly = 1
Select Count(*)
From TableA A
Join TableB B On etc. etc...
Where < here put all Filtering predicates >
Else
<Here put old SQL That returns complete resultset with all data>
Return 0
@CountsOnly を 1 に設定して同じストアド プロシージャを呼び出すだけで、レコード数を取得できます。proc を呼び出す古いコードは、パラメーター値が含まれていない場合、デフォルトで false (0) に設定されているため、以前と同じように機能します。
結果セットを一時テーブルに入れる手順を実行することは、少なくとも技術的には可能です。次に、データをサーバーからアプリケーションに移動する前に行数を見つけることができ、結果セットを 2 回作成する必要がなくなります。
しかし、結果セットの作成に非常に長い時間がかからない限り、問題を起こす価値があるとは思えません。その場合、一時テーブルが問題になるほど大きくなる可能性があります。大きなテーブルをネットワーク上で移動する時間は、作成に必要な時間の何倍にもなります。