16

テーブル値関数からいくつかの行を選択していますが、クエリに SELECT TOP を入れると、説明のつかない大きなパフォーマンスの違いが見つかりました。

SELECT   col1, col2, col3 etc
FROM     dbo.some_table_function
WHERE    col1 = @parameter
--ORDER BY col1

完了するまでに 5 ~ 6 分以上かかります。

でも

SELECT   TOP 6000 col1, col2, col3 etc
FROM     dbo.some_table_function
WHERE    col1 = @parameter
--ORDER BY col1

約4、5秒で完了します。

返されたデータのセットが膨大であったとしても、これは驚くことではありませんが、関連する特定のクエリは 200,000行から5,000 行を返します。

そのため、どちらの場合も、SQL Server が 6000 行を最後まで検索し続けるため、テーブル全体が処理されますが、到達することはありません。では、なぜ大きな違いがあるのでしょうか。これは、SQL Server が結果セットのサイズを見越してスペースを割り当てる方法と関係がありますか (TOP 6000 により、メモリ内でより簡単に割り当てられる要件が低くなります)。他の誰かがこのようなことを目撃しましたか?

ありがとう

4

6 に答える 6

8

テーブル値関数は、非線形の実行時間を持つことができます。

このクエリに相当する関数を考えてみましょう。

SELECT  (
        SELECT  SUM(mi.value)
        FROM    mytable mi
        WHERE   mi.id <= mo.id
        )
FROM    mytable mo
ORDER BY
        mo.value

このクエリ (実行中の を計算するSUM) は、最初は高速で、最後は低速moです。これは、各行で前のすべての値を合計する必要があり、rowsource を巻き戻す必要があるためです。

SUM行番号が増えると、各行の計算にかかる時間が長くなります。

十分なmytable大きさ (たとえば、100,000例のように行) を作成してこのクエリを実行すると、かなりの時間がかかることがわかります。

ただし、このクエリを適用すると、テーブル全体に必要な時間TOP 5000よりもはるかに速く完了することがわかります。1/20

おそらく、あなたのケースでも同様のことが起こります。

より明確に言うと、関数定義を確認する必要があります。

アップデート:

SQL Server述語を関数にプッシュできます。

たとえば、これを作成しましたTVF

CREATE FUNCTION fn_test()
RETURNS TABLE
AS
RETURN  (
        SELECT  *
        FROM    master
        );

これらのクエリ:

SELECT  *
FROM    fn_test()
WHERE   name = @name

SELECT  TOP 1000 *
FROM    fn_test()
WHERE   name = @name

異なる実行プランを生成します (最初のものはクラスター化されたスキャンを使用し、2 つ目は を使用したインデックス シークを使用しますTOP)

于 2009-09-08T11:45:37.600 に答える
5

私は同じ問題を抱えていました.1000行を返す5つのテーブルを結合する単純なクエリは、完了するのに2分かかりました. そこに「TOP 10000」を加えると、1秒もかからずに完了しました。いずれかのテーブルのクラスター化インデックスが大幅に断片化されていることが判明しました。

インデックスを再構築した後、クエリは 1 秒未満で完了するようになりました。

于 2015-07-03T07:59:46.187 に答える
4

TOP には ORDER BY がないため、最初に SET ROWCOUNT 6000 を実行するのと同じです。ORDER BY では、最初にすべての行を評価する必要があり、さらに時間がかかります。

が udf 値のインライン テーブルである場合dbo.some_table_function、それは展開された単なるマクロであり、特定の順序で言及されているように、最初の 6000 行を返します。

UDF が複数の値を持つ場合、それはブラック ボックスであり、フィルタリングする前に常に完全なデータセットを取り込みます。私はこれが起こっているとは思わない。

直接関係はありませんが、TVF に関する別の SO の質問

于 2009-09-08T12:14:57.937 に答える
1

Quassnois の提案は非常にもっともらしいと思います。TOP 6000 を追加することで、200,000 行のかなり小さなサブセットが返されるというヒントを暗黙的にオプティマイザーに与えます。その後、オプティマイザーはクラスター化インデックス スキャンまたはテーブル スキャンの代わりにインデックス シークを使用します。

ジム・デイビスが示唆するように、別の考えられる説明はキャッシングである可能性があります。これは、クエリを再度実行することで簡単に除外できます。最初に TOP 6000 のものを実行してみてください。

于 2009-09-08T12:48:50.350 に答える
1

ここでキャッシュするのと同じくらい簡単なことに出くわしているかもしれません-おそらく(何らかの理由で)「TOP」クエリがキャッシュされていますか? 他にはないインデックスを使用していますか?

いずれにせよ、好奇心を抑える最善の方法は、両方のクエリの完全な実行計画を調べることです。SQL 管理コンソールでこれを行うと、どの操作が完了しているか、それぞれにかかる時間が予測されることが正確にわかります。

すべての SQL 実装は独自の方法で風変わりです - SQL Server も例外ではありません。こういう「わあああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ!瞬間はかなり一般的です。;^)

于 2009-09-08T11:56:50.993 に答える
1

col1 にインデックスがある場合、テーブル全体が処理されるとは限りません。

SQL 最適化では、インデックスを使用するかどうかが選択されます。おそらく、「TOP」がインデックスの使用を強制している可能性があります。

MSSQL Query Analyzer を使用している場合 (名前は省略します)、Ctrl-K を押します。これにより、クエリを実行する代わりに、クエリの実行プランが表示されます。アイコンの上にマウスを置くと、IO/CPU 使用率が表示されると思います。

1 つはインデックス シークを使用していて、もう 1 つは使用していないに違いありません。

汎用クライアントの場合: SET SHOWPLAN_ALL ON; GO 選択 ...; 行く

詳細については、 http://msdn.microsoft.com/en-us/library/ms187735.aspxを参照してください。

于 2009-09-08T11:53:03.323 に答える