ちょっと質問がありました。テーブルの単一の最大値を取得しようとするとき。どちらがいいですか?SQLパフォーマンスMAX()
SELECT MAX(id) FROM myTable WHERE (whatever)
または
SELECT TOP 1 id FROM myTable WHERE (whatever) ORDER BY id DESC
は、私が最初のものは確かに意思で明確にされているMicrosoft SQL Server 2012の
ちょっと質問がありました。テーブルの単一の最大値を取得しようとするとき。どちらがいいですか?SQLパフォーマンスMAX()
SELECT MAX(id) FROM myTable WHERE (whatever)
または
SELECT TOP 1 id FROM myTable WHERE (whatever) ORDER BY id DESC
は、私が最初のものは確かに意思で明確にされているMicrosoft SQL Server 2012の
実行計画を検査して自分自身をテストすることはできますが、違いはありません。 id
がクラスタード・インデックスの場合は、順序付きクラスタード・インデックス・スキャンが表示されます。索引付けされていない場合でも、表スキャンまたはクラスタード・インデックス・スキャンのいずれかが表示されますが、いずれの場合も順序付けされません。
TOP 1
のアプローチは、行から他の値を引き出す場合に便利です。これは、サブクエリでmaxを引っ張って結合するほうが簡単です。行の他の値が必要な場合は、どちらの場合でもタイを扱う方法を指定する必要があります。
これは、計画が異なる可能性があるシナリオがいくつかあるため、列が索引付けされているかどうか、単調に増加しているかどうかによってテストすることが重要です。スルー2010-01-01からE/G、3と9994の間のB/D、これは1から50000まで/ Cの値を作成し、私のシステムで
CREATE TABLE dbo.x
(
a INT, b INT, c INT, d INT,
e DATETIME, f DATETIME, g DATETIME, h DATETIME
);
CREATE UNIQUE CLUSTERED INDEX a ON dbo.x(a);
CREATE INDEX b ON dbo.x(b)
CREATE INDEX e ON dbo.x(e);
CREATE INDEX f ON dbo.x(f);
INSERT dbo.x(a, b, c, d, e, f, g, h)
SELECT
n.rn, -- ints monotonically increasing
n.a, -- ints in random order
n.rn,
n.a,
DATEADD(DAY, n.rn/100, '20100101'), -- dates monotonically increasing
DATEADD(DAY, -n.a % 1000, '20120101'), -- dates in random order
DATEADD(DAY, n.rn/100, '20100101'),
DATEADD(DAY, -n.a % 1000, '20120101')
FROM
(
SELECT TOP (50000)
(ABS(s1.[object_id]) % 10000) + 1,
rn = ROW_NUMBER() OVER (ORDER BY s2.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS n(a,rn);
GO
:私は、単純なテーブルを作成し、50000個の行を挿入しました2011-05-16、およびf/hを2009-04-28から2012-01-01まで変更できます。
まず、索引付けされた単調増加整数列aとcを比較してみましょう。 、cは、クラスタ化インデックスはありませんしています
SELECT MAX(a) FROM dbo.x;
SELECT TOP (1) a FROM dbo.x ORDER BY a DESC;
SELECT MAX(c) FROM dbo.x;
SELECT TOP (1) c FROM dbo.x ORDER BY c DESC;
結果:第4回のクエリで
大きな問題はMAX
とは異なり、それはソートを必要とする、ということです。ここで4と比較して3:
これは、これらのクエリー変形の全てに共通の問題であろう。索引付けされていない列に対するMAX
は、クラスタ上でピギーバックすることができるであろうインデックススキャンを実行し、ストリーム集約を実行しますが、TOP 1
はより高価になるソートを実行する必要があります。
私は、b + d、e + g、およびf + hのテストで全く同じ結果をテストして見ました。
だから、あなたが置かれているの後に変更することができた(より標準準拠のコードを生成することに加えて、基本となるテーブルやインデックスに応じて、TOP 1
の賛成でMAX
を使用する潜在的なパフォーマンス上の利点がある、と私には思われますプロダクションでのあなたのコード)。だから私は、詳細情報なしで、MAX
が好ましいと言います。
TOP 1
は本当にあなたが追加の列を引っ張っている場合は、後にしている行動かもしれません。あなたはそれはあなたが後にしているものだ場合にも
MAX
+
JOIN
メソッドをテストしたいと思います。 )
+1 - あなたのパーセンテージを計算するために使用されたSQLはどれですか?または実行計画のXMLを調べましたか?将来の読者にも、これらの計画を尋ねる方法についての知識が与えられるように、あなたの答えにそのことを載せていただければ幸いです。 – Wayne
私の会社の無料ツールであるSQL Sentry Plan Explorerの関連出力を表示しました。 http://sqlsentry.net/ –
[トップNのソートについての良い記事はこちら](http://sqlblog.com/blogs/paul_white/archive/2010/08/27/sorting-row-goals-and) -the-top-100-problem.aspx)誰かが興味があれば。実際にはすべての行をソートする必要はなく( 'TOP 1 'を追跡する必要があります)、ストリーム集約とは異なりメモリの付与が必要です。 –
を使用しています。
この特定のクエリでは、重要なパフォーマンスの違いは考えられません(myTable
に行がない場合は結果が異なりますが、実際にはほとんど同じです)。クエリを調整する正当な理由(例:実績のあるパフォーマンスの問題)がない限り、常にコードの意図を示すものを選択します。
もう1つの利点は、最初のクエリがDBMSに依存しないということです。つまり、同じクエリを使用して他のほぼすべてのDBMSで実行することができ、それでも機能しますが、2番目のクエリはSQL Server固有の ' 'キーワードはSQL-Serverでのみサポートされています。 –
すべてのクエリオプティマイザは、両方のクエリで同じパフォーマンスを持つクエリプランを生成する必要があります。最適化する列にインデックスがある場合、両方のクエリで使用する必要があります。索引がない場合、両方とも完全な表スキャンを生成します。
私は、TOP 1ソート演算子がプランでコストオーバーされていると思われます。私はTOP 1、TOP 100、> TOP 101を試してみましたが、すべての行を並べ替える必要があるという事実にもかかわらず、私は同じサブツリーコストを払ってくれました。 - 午前6時53分あなたはオプティマイザがすなわちテーブル(クラスタ化インデックス・スキャン).Thenからすべての行を読んで、この例では仕事の同じ量を行う必要があります1行または100行が必要かどうか
でマーティン・スミス7月2日列Cに索引がないので、すべての行をソートする(ソート操作)。最後に必要なものだけを表示する。
上記のコードを試してください。ここでは、トップ1とトップ100は、b列にインデックスがあるため、差額を示しています。したがって、この場合、すべての行を読み込んで並べ替える必要はありませんが、作業は最終ページポインタに移動することです.1つの行では、インデックスの最後の葉ページの最後の行を読み込みます。 TFor 100行は最後の行を最後のページで見つけ出し、100行を取得するまで後方スキャンを開始します。
これは正しくありません。 [私が与えたリンクは 'TOP N'ソートの仕組みについて説明しています(http://sqlblog.com/blogs/paul_white/archive/2010/08/27/sorting-row-goals-and-the-top)をお読みください。 -100-problem.aspx)。 100はさまざまな方法の間のマジックナンバーですが、Aaronのデモデータを実行しているときに、「TOP 1」と「TOP 50000」のコストが同じであるため、計画の原価計算で考慮されるようには見えません。'TOP 1'の場合、基本的には、MAXが異なる方法で実装されているにもかかわらず、MAXと同じ最大値を追跡する必要があります。 50,000行すべてをソートする必要はありません。 –
50000行をソートしない場合リストにソートされていないと言われた場合、どの値が最大値であるかは分かりますか?列Cにはインデックスがありません。 –
すべてをスキャンし、これまでに見てきた 'TOP 1 'の値とそれぞれを比較します。 50,000行のセット全体を並べ替える必要はありません。 –
テストしましたか?私は彼らがオプティマイザが良い場合は、同じであることを期待するだろう。 – Hogan
'id'が自動インクリメントの場合、この質問はhttp://stackoverflow.com/questions/590079/for-autoincrement-fields-maxid-vs-top-1-id-order-by-id-descの複製です – Ben
idは任意のタイプの任意の列を意味します –