これらのクエリには大きな違いがあります。SQLはなぜSELECT COUNT(*)、MIN(col)、MAX(col)の方が速いのですか?SELECT MIN(col)、MAX(col)
スロークエリ
SELECT MIN(col) AS Firstdate, MAX(col) AS Lastdate
FROM table WHERE status = 'OK' AND fk = 4193
テーブル 'テーブル'。スキャンカウント2、論理読み取り2458969、物理読み取り0、先読み読み取り0、論理読み取り0、論理読み取り0、論理読み取り0、読み取り先読み0のロブ。
SQL Server実行時間:CPU時間= 1966 ms 、経過時間= 1955ms。
速いクエリ
SELECT count(*), MIN(col) AS Firstdate, MAX(col) AS Lastdate
FROM table WHERE status = 'OK' AND fk = 4193
テーブル 'テーブル'。スキャンカウント1、論理読み取り5803、物理読み取り0、先読み読み取り0、論理読み取り0、論理読み取り0、論理読み取り0、読み取り先読みLOB 0
SQL Server実行時間:CPU時間= 0 ms 、経過時間= 9ms。
質問
クエリの間に大きなパフォーマンスの差の理由は何ですか?
更新 コメントとして与えられた質問に基づいて、少し更新:
実行または繰り返し実行の順序は、賢明な何も性能が変化します。 追加のパラメータは使用されておらず、(テスト)データベースは実行中に何も実行していません。
スロークエリ
|--Nested Loops(Inner Join)
|--Stream Aggregate(DEFINE:([Expr1003]=MIN([DBTest].[dbo].[table].[startdate])))
| |--Top(TOP EXPRESSION:((1)))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1008]) WITH ORDERED PREFETCH)
| |--Index Scan(OBJECT:([DBTest].[dbo].[table].[startdate]), ORDERED FORWARD)
| |--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[FK]=(5806) AND [DBTest].[dbo].[table].[status]<>'A') LOOKUP ORDERED FORWARD)
|--Stream Aggregate(DEFINE:([Expr1004]=MAX([DBTest].[dbo].[table].[startdate])))
|--Top(TOP EXPRESSION:((1)))
|--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1009]) WITH ORDERED PREFETCH)
|--Index Scan(OBJECT:([DBTest].[dbo].[table].[startdate]), ORDERED BACKWARD)
|--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[FK]=(5806) AND [DBTest].[dbo].[table].[status]<>'A') LOOKUP ORDERED FORWARD)
高速クエリ
|--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1012],0)))
|--Stream Aggregate(DEFINE:([Expr1012]=Count(*), [Expr1004]=MIN([DBTest].[dbo].[table].[startdate]), [Expr1005]=MAX([DBTest].[dbo].[table].[startdate])))
|--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1011]) WITH UNORDERED PREFETCH)
|--Index Seek(OBJECT:([DBTest].[dbo].[table].[FK]), SEEK:([DBTest].[dbo].[table].[FK]=(5806)) ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[status]<'A' OR [DBTest].[dbo].[table].[status]>'A') LOOKUP ORDERED FORWARD)
回答
は下記の答えMartin Smithはこの問題を説明しているようです。極短いバージョンは、MS-SQLクエリアナライザが完全なテーブルスキャンを引き起こす低速クエリでクエリプランを間違って使用することです。
カウント(*)を追加すると、(FORCESCAN)のクエリヒントまたは開始日、FKおよびステータス列の結合インデックスによって、パフォーマンスの問題が修正されます。
2番目のクエリの後に1番目のクエリを実行するとどうなりますか? – gbn
カウント(*)を使用している場合、fk = 4193のすべてのレコードをチェックしない可能性がありますか? – nosbor
これを実行していますか?もしそうなら、両方のクエリの前に 'DBCC DROPCLEANBUFFERS'と' DBCC FREEPROCCACHE'を置くとどうなりますか?シーケンスを変更するとどうなりますか?最初に高速クエリを実行した後、遅いクエリを実行します。 –