ストアドプロシージャを実行する前に行数を取得できますか?
-
05-07-2019 - |
質問
数千行を返す可能性のある複雑なストアドプロシージャがあり、完了するまでに長い時間がかかります。
クエリが実行されてデータを取得する前に返される行数を調べる方法はありますか?
これは、WinformsアプリケーションであるVisual Studio 2005およびSQL Server 2005で使用されます。
解決
問題の解決策は、次のように結果セットをある数に制限するようにストアドプロシージャを書き直すことです。
SELECT TOP 1000 * FROM tblWHATEVER
SQL Serverで、または
SELECT * FROM tblWHATEVER WHERE ROWNUM <= 1000
Oracleの。または、各呼び出しの結果セットが許容できるほど小さくなるように、ページングソリューションを実装します。
他のヒント
ストアドプロシージャの完了には時間がかかると述べました。データベースから行を選択するプロセス、または呼び出し元に行を返すプロセスの大部分の時間がかかっていますか?
後者の場合、実際の行ではなくカウントを取得するSPのミラーバージョンを作成できます。前者の場合は、適格な行を見つける行為であるため、実際にはそれほど多くのことはできません。
最初に行をカウントするストアドプロシージャを作成します。
テーブルからSELECT COUNT(*)
これを計算できるアプリのビジネスロジックの側面がない限り、いいえ。すべての場所で&amp;を実行する必要があるデータベース。ロジックを結合して行の行を把握します。これが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;
一般的ではありません。
ストアドプロシージャの操作に関する知識により、推定値または正確なカウントを取得できる場合があります(たとえば、クエリの&quot; core&quot;または&base&quot;テーブルをすばやく取得できる場合計算されますが、複雑な結合や要約が時間を増加させます。
ただし、最初にカウントSPを呼び出してからデータSPを呼び出すか、複数の結果セットSPの使用を検討する必要があります。
行カウントを取得するのに実際のデータを取得するのと同じくらい時間がかかる可能性があるため、ほとんどの場合、カウントの実行を推奨しません。
いくつかの可能性:
1)SQL Serverは、クエリオプティマイザーの結果を何らかの方法で公開していますか?つまり、クエリを解析してから行数の推定を取得できますか? (SQL Serverがわかりません)。
2)おそらく、ユーザーが指定した基準に基づいて、独自の推定を実行できます。たとえば、ユーザーが顧客の姓フィールドに「S%」と入力して注文を照会すると、顧客レコードの7%(たとえば)に一致すると判断し、クエリが を返すと推定できます注文記録の7%。
トニー・アンドリュースが答えで言ったことを続けると、クエリの呼び出しの推定クエリプランを取得できます。
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つまたは複数のテーブルが返されます。
返されるデータセットを分析し、返される結果セットの論理的な(意味のある)主キーを決定する必要があります。通常、サーバーは各テーブルの各行のすべての列のデータから結果セットを構築するのではなく、単に行をカウントするだけなので、完全な手順よりもはるかに高速です。これを行うには、ディスクから実際のテーブル行を読み取る必要があります。単にインデックスノードをカウントする必要がある場合があります...
次に、これらのキー列を生成するために必要なテーブルのみを含む別のSQLステートメント(これはメインのSQLクエリのテーブルのサブセットです)、および同じフィルタリング述語値を持つ同じwhere句を記述します...
次に、デフォルトのfalse(0)を使用して、たとえば@CountsOnlyと呼ばれる別のオプションパラメーターをストアドプロシージャに追加します...
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回作成する必要がなくなります。
しかし、結果セットの作成に非常に長い時間がかかる場合を除き、トラブルに見合うだけの価値はないと思います。その場合、一時テーブルが問題になるほど十分に大きい可能性があります。ほぼ確実に、ネットワーク上で大きなテーブルを移動する時間は、テーブルを作成するために必要な時間の何倍にもなります。