SARGカーディナリティの推定、なぜフルスキャンではないのですか?


11

フルスキャンがないのはなぜですか(SQL 2008 R2および2012)。

テストデータ:

DROP TABLE dbo.TestTable
GO  
CREATE TABLE dbo.TestTable
(
   TestTableID INT IDENTITY PRIMARY KEY,
   VeryRandomText VarChar(50),
   VeryRandomText2 VarChar(50)
)
Go
Set NoCount ON
Declare @i int
Set @i = 0
While @i < 10000
Begin
   Insert Into dbo.TestTable(VeryRandomText, VeryRandomText2)
      Values(Cast(Rand()*10000000 as VarChar(50)), Cast(Rand()*10000000 as VarChar(50)));
   Set @i = @i + 1;
End
Go
CREATE Index IX_VeryRandomText On dbo.TestTable
(
    VeryRandomText
)
Go

クエリを実行すると:

Select * From dbo.TestTable Where VeryRandomText = N'111' -- bad

警告を取得します(ncharデータをvarchar列と比較しているため、予想どおり)。

<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(nvarchar(50),[DemoDatabase].[dbo].[TestTable].[VeryRandomText],0)" />

しかし、実行プランが表示され、予想どおりフルスキャンを使用していないことがわかります。代わりにインデックスシークを使用しています。

ここに画像の説明を入力してください

もちろん、これは一種の良いことです。なぜなら、この特定のケースでは、フルスキャンの場合よりも実行がはるかに高速だからです。

しかし、私はSQLサーバーがどのようにしてこの計画を立てる決断をしたのか理解できません。

また、サーバー照合がサーバーレベルとSQL Server照合データベースレベルのWindows照合である場合、同じクエリでフルスキャンが発生します。

回答:


8

異なるデータ型の値を比較する場合、SQL Serverはデータ型優先規則に従います。nvarcharはvarcharよりも優先順位が高いため、SQL Serverは値を比較する前に列データをnvarcharに変換する必要があります。これは、列に関数を適用することを意味し、クエリを検索できないようにします。

ただし、SQL Serverは間違いからユーザーを保護するのが最善の方法です。そのため、ブログ投稿のDynamic SeeksとHidden Implicit Conversionsで Paul Whiteが説明した手法を使用して、値の範囲を検索し、最終的な比較を行います。列の値をnvarcharに変換し、残差述語で偽陽性を除外します。

ただし、列の照合がSQL照合の場合は機能しません。その理由は、SQL照合とWindows照合の比較の記事に記載されていると思います。

基本的に、Windows照合はvarcharとnvarcharに同じアルゴリズムを使用し、SQL照合はvarcharデータに異なるアルゴリズムを使用し、nvarcharデータにWindows照合と同じアルゴリズムを使用します。

したがって、Windows照合でvarcharからnvarcharに移行すると、同じアルゴリズムが使用され、SQL Serverは、nvarcharリテラルから値の範囲を生成して、varchar SQL照合列インデックスから行を取得できます。ただし、varchar列の照合がSQL照合である場合は、使用されているアルゴリズムが異なるため不可能です。


更新:

ウィンドウとSQL照合を使用したvarchar列のさまざまな並べ替え順序のデモ。

SQLフィドル

MS SQL Server 2014スキーマのセットアップ

create table T(C varchar(10));

insert into T values('a-b'),('aa'),('ac');

クエリ1

select C
from T
order by C collate SQL_Latin1_General_CP1_CI_AS;

結果

|   C |
|-----|
| a-b |
|  aa |
|  ac |

クエリ2

select C
from T
order by C collate Latin1_General_100_CI_AS;

結果

|   C |
|-----|
|  aa |
| a-b |
|  ac |

0

非クラスタ化インデックスのリーフノードは、データ行を見つけるためのクラスタリングキーまたはRIDを含むインデックスページで構成されていることを覚えておく必要があります。

where句でVeryRandomText = N'111'、VeryRandomTextに非クラスター化インデックスがあるため(クラスター化を作成するように明示的に指示しない限り、インデックスを作成すると非クラスター化インデックスが作成されます)、データを見つける最も簡単な方法は、インデックスをスキャンしてROWIDと次に、行のデータをフェッチします。

クラスタ化インデックスを作成する場合

CREATE clustered Index IX_VeryRandomText On dbo.TestTable (VeryRandomText)

またはVeryRandomTextの主キーでは、そのインデックスのスキャンを取得します。

オンラインまたはこちらの本を参照してください。http//www.sqlforge.com/w/Clustered_index,_nonclustered_index,_or_heap


はい、私はあなたが書いていることを知っています。ご覧のとおり、TestTableIDには既にクラスター化インデックスがあります。ただし、SQLサーバーが列データの分布の統計を確認できない場合(この場合、すべての行の値のデータ型変換が必要なデータ型の不一致が原因で)、この場合はインデックスシークではなくクラスター化インデックススキャンを選択する必要があります。 。
ジャニス・

また、非クラスター化インデックスをシーク/スキャンするのが常に最も安いとは限りません。値が十分に区別されていない場合やカバーしていないインデックスの場合は、代わりにクラスター化インデックススキャンを実行する方が安価な場合があります。
2015

あなたはクエリプランを読めば、インデックスが(非クラスタ化)しようと同じ-ジャニス@インデックスはあなたがそう明示的に言っているクラスタ化インデックスを作成しません作成スクリプトにaccoringない
Spörri

「PRIMARY KEY制約を作成すると、テーブルのクラスター化インデックスがまだ存在せず、一意の非クラスター化インデックスを指定しない場合、列または列に一意のクラスター化インデックスが自動的に作成されます。」msdn.microsoft.com/en-us/library/ms186342.aspx
ジャニス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.