これらの質問と与えられた回答に基づいて:
SQL 2008 Server-非常に大きなテーブルに接続されているとパフォーマンスが低下する可能性があります
履歴データを含む大きなテーブルがSQL Server 2008標準メモリを割り当てすぎます-他のデータベースのパフォーマンスが低下します
データベースSupervisionPに次のように定義されたテーブルがあります。
CREATE TABLE [dbo].[PenData](
[IDUkazatel] [smallint] NOT NULL,
[Cas] [datetime2](0) NOT NULL,
[Hodnota] [real] NULL,
[HodnotaMax] [real] NULL,
[HodnotaMin] [real] NULL,
CONSTRAINT [PK_Data] PRIMARY KEY CLUSTERED
(
[IDUkazatel] ASC,
[Cas] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[PenData] WITH NOCHECK ADD CONSTRAINT [FK_Data_Ukazatel] FOREIGN KEY([IDUkazatel])
REFERENCES [dbo].[Ukazatel] ([IDUkazatel])
ALTER TABLE [dbo].[PenData] CHECK CONSTRAINT [FK_Data_Ukazatel]
これにはcca 211ミリオンの行が含まれます。
私は次のステートメントを実行します:
DECLARE @t1 DATETIME;
DECLARE @t2 DATETIME;
SET @t1 = GETDATE();
SELECT min(cas) from PenData p WHERE IDUkazatel=24
SELECT min(cas) from PenData p WHERE IDUkazatel=25
SET @t2 = GETDATE();
SELECT DATEDIFF(millisecond,@t1,@t2) AS elapsed_ms;
SET @t1 = GETDATE();
SELECT min(cas) from PenData p WHERE IDUkazatel=24 OR IDUkazatel=25
SET @t2 = GETDATE();
SELECT DATEDIFF(millisecond,@t1,@t2) AS elapsed_ms;
結果は次のとおりです。
3番目のSELECTは、SQL Serverメモリキャッシュにさらに多くのデータをロードします。
3番目のSELECTが最初の2つのSELECT(16ミリ秒)よりもはるかに遅い(8.5秒)のはなぜですか? ORを使用して3番目の選択のパフォーマンスを向上させるにはどうすればよいですか?次のSQLコマンドを実行したいのですが、この場合、単一の選択よりもカーソルの作成と個別のクエリの実行の方がはるかに速いようです。
SELECT MIN(cas) from PenData p WHERE IDUkazatel IN (SELECT IDUkazatel FROM ...)
[〜#〜]編集[〜#〜]
デビッドが示唆したように、私は太い矢印の上にカーソルを合わせました:
最初の2つのクエリでは、クラスタードインデックスをスキャンしてIDUkazatel
のその値の最初のエントリをスキャンするだけです。インデックスの順序により、その行はIDUkazatel
のその値のcasの最小値になるためです。
2番目のクエリでは、この最適化は値ではなく、おそらく_IDUkazatel=24
_の最初の行を検索してから、_IDUkazatel=25
_で最後の行までインデックスをスキャンして、それらすべての行でcas
の最小値を見つけます。
その太い矢印の上にカーソルを合わせると、多くの行(確かに24のすべての行、おそらく25の行もすべて)が読み取られているのがわかりますが、他の2つの計画の出力の細い矢印は、top
アクションを示しています。 1行のみを考慮します。
各クエリを実行してから、見つかった最小値の最小値を取得できます。
_SELECT MIN(cas)
FROM (
SELECT cas=MIN(cas) FROM PenData p WHERE p.IDUkazatel = 24
UNION ALL
SELECT cas=MIN(cas) FROM PenData p WHERE p.IDUkazatel = 25
) AS minimums
_
つまり、明示的なIDUkazatel
句ではなく、OR
値を含むテーブルがあるようです。以下のコードはその配置で機能し、テーブル名_@T
_をIDUkazatel
値を含むテーブルの名前に置き換えるだけです。
_SELECT
MinCas = MIN(CA.PartialMinimum)
FROM @T AS T
CROSS APPLY
(
SELECT
PartialMinimum = MIN(PD.Cas)
FROM dbo.PenData AS PD
WHERE
PD.IDUkazatel = T.IDUkazatel
) AS CA;
_
理想的な世界では、SQL Serverクエリオプティマイザーがこの書き換えを実行しますが、現在このオプションが常に考慮されているとは限りません。