これは4億を超える行と16の非クラスター化インデックス、146列のヒープです。クラスタ化インデックスを作成できない理由に焦点を当てないでください。それは私の管理下にはなく、私の質問の範囲にもありません。
SQLサーバー:
Microsoft SQL Server 2012(SP4-GDR)(KB4057116)-11.0.7462.6(X64)Jan 5 2018 22:11:56 Copyright(c)Microsoft Corporation Enterprise Edition:Core-based Licensing(64-bit)on Windows NT 6.3(ビルド9600:)(ハイパーバイザー)データベース互換性レベル:SQL Server 2008(100)
次のクエリ(匿名化)を実行すると、 この実際の実行プランが取得されます 。
SELECT TOP ? *
FROM Schema1.Object1 Object2
WHERE Object2.Column1 LIKE ?
ORDER BY Object2.Column2 DESC
同じデータベースをSQL 2017 CU13に復元し、互換モードをSQL Server 2012(110)に変更します(以下は完全なバージョン名です)。私は この実際の実行計画 を取得します。
Microsoft SQL Server 2017(RTM-CU13)(KB4466404)-14.0.3048.4(X64)2018年11月30日12:57:58 Copyright(C)2017 Microsoft Corporation Enterprise Edition(64-bit)on Windows Server 2016 Standard 10.0(Build 14393 :)(ハイパーバイザー)
ここで「ROW GOAL」が活躍していることはよくわかりました。これは以前にクエリプランで公開されていなかったため、最初のプランでは表示できません。 Trace Flag 4138を使用してSQL Server 2008バージョンを実行し、DISABLE_OPTIMIZER_ROWGOAL
ヒントを使用してSQL Server 2012バージョンを実行できることを確認します。どちらの場合も、パフォーマンスが大幅に向上します。オプティマイザが正しいインデックスを選択し、nested loop join
を選択しないため、ゲインが発生します。
質問:
EstimatedRowsWithoutRowGoal
(2008年には表示されないことを理解しています)が異なるのですか?私は Paul Whiteの記事 と記事に記載されている8つのリンクすべてを読みました。また、 をご覧ください。Showplanのその他の機能強化– Pedro Lopesによる行の目標
2つのクエリ(およびテーブル?)が完全に一致しません。
SQL Server 2008互換性レベルクエリには143列が返されますSQL Server 2012互換性レベルクエリには146列がありますが返されます。
これらの表の他の違いを確認してください。
インデックススキャンがSQL 2008の110万行とSQL 2012の870万行を比較するのはなぜですか?
インデックススキャンはObject2.Column2
で並べ替えられた行を返し、ブックマークをプッシュします
(匿名化計画のブックマーク= column144
/Column147
)
Object2.Column1
でRIDルックアップとフィルタリングを行います。
最初の推測:ネクタイ?
これにより、Object2.Column2
にはタイがあるため、最初に異なる行が読み取られると思います。
両方が順序付けられたプリフェッチを実行しています
<NestedLoops Optimized="0" WithOrderedPrefetch="1">
...順序付けされたプリフェッチは、ネストされたループ結合の内側でキーの順序を保持するため、SQL Serverは非同期I/Oが正しい順序で処理されるようにします。 ...テストクエリには、オプティマイザが順序付きプリフェッチを使用してソートを回避できるORDER BY句が含まれています...
私は間違っているかもしれませんが、これから私が取るのは、順序が保持されている限り、異なる行が[〜#〜] rid [〜#〜]tieクレームをサポートするルックアップ演算子。
一意の順序でクエリを実行し、これらのクエリプランを質問に追加してみてください。
どちらの互換性レベルもSQL Server 2014バージョンより前であるのに、EstimatedRowsWithoutRowGoal(2008年には表示されないことを理解しています)が異なるのはなぜですか?
ここで詳細な統計情報が必要になります。統計はテーブル間で異なる推定値を示し、EstimatedRowsWithoutRowGoal
に違いが生じます
同じ量の列を選択して両方のクエリを実行する前に、フルスキャン更新を実行してみてください。
テスト
SQL Serverインスタンス(2008)と(2017と互換性のある2012)の間でテストを行う場合
同じ量の行が返されます。
2008(互換性):
2012(互換性):
Column2を変更して多くの重複を保持する場合でも、見積もりと実績は同じままです。
UPDATE dbo.Object1
SET Object1.Column2
= Object1.Column2 % 400;
予想どおり、compat 2012 dbのテーブルに追加の列を追加しても、見積もりは同じままです
ALTER TABLE dbo.Object1
ADD ExtraColumn1 int default(1) with values;
ALTER TABLE dbo.Object1
ADD ExtraColumn2 int default(2) with values;
ALTER TABLE dbo.Object1
ADD ExtraColumn3 int default(3) with values;
トレースフラグを有効にした同じストーリー
結論
この種のデータは、データのつながりに関する以前のステートメントを除外しますが、データセット(はるかに小さい)で問題を再現できないことも示しています。
column2
全体を同じ値に設定しても、返される行の量に違いはありません。データの違いが原因のようです。
使用されるデータセット
CREATE DATABASE TEST
GO
USE [master]
GO
ALTER DATABASE [TEST] MODIFY FILE ( NAME = N'TEST', FILEGROWTH = 1048576KB )
GO
ALTER DATABASE [TEST] MODIFY FILE ( NAME = N'TEST_log', FILEGROWTH = 1048576KB )
GO
alter database test set recovery simple
GO
backup database test to disk = 'NUL'
GO
use TEST
go
CREATE TABLE dbo.Object1(
Column1 int,
Column2 int,
Column3 int,
Column4 int,
Column5 int,
Column6 int,
Column7 int,
Column8 int,
Column9 int,
Column10 int,
Column11 int,
Column12 int,
Column13 int,
Column14 int,
Column15 int,
Column16 int,
Column17 int,
Column18 int,
Column19 int,
Column20 int,
column1_varchar varchar(20));
CREATE INDEX Index1
on dbo.Object1(column15,Column16,Column17)
CREATE INDEX Index2
on dbo.Object1(Column2,Column10,Column19)
SELECT top(1000000) --1M
row_number() over(order by (select null)) as rownum
INTO #temp
FROM master..spt_values spt1
cross apply master..spt_values spt2
cross apply master..spt_values spt3
INSERT INTO dbo.Object1
WITH(TABLOCK)
SELECT
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
rownum,
'ABC'+ CAST(rownum as varchar(20))
FROM #temp
GO 3
Randi Vertongenの回答は、最初の質問で提供した情報に基づいて期待できる最高のものです。他の読者のためにコメントすることはできないので、これは答えとしてのみ書いています。免責事項:ランディと私はこれについてチャットしました ここ 。
一度の情報は、あなたが従うのに役立ちます。 where句を含む上位100件の結果セットでは、すべての結果がcolumn2の値829000514900
に属しています。
データセットは、2つの環境のヒープで完全に異なります。 column2に基づいてローリング合計を行うことにしました。
これが私が見つけたものです。小さな違いがまだ存在していると私は考えています[Forwarded Record][2]
]がヒープにあります。
両方の環境でクエリの下を実行しました。
SELECT
column2,
COUNT(0) AS CountColumn2,
SUM (COUNT(column2)) OVER (ORDER BY column2 DESC) AS RunningTotal
FROM dbo.object1
GROUP BY column2
ORDER BY column2 DESC
SQL Server 2008環境の結果:
読み込まれた行の実際の数= 1176085
colum2 CountColumn2 RunningTotal
829000515000 79 1175804
829000514900 159 1175963
829000514800 631 1176594
SQL Server 2012環境の結果:
読み取られた実際の行数= 8891415
colum2 CountColumn2 RunningTotal
829000515000 79 8892962
829000514900 159 8893121
829000514800 631 8893752