次のスキーマとクエリを想定します。
intsであると予想されるvarchar列に値があることに関する明白な設計の問題を過去に見てください。
create table dbo.Parent (
Id bigint NOT NULL,
TypeId int NOT NULL
)
create table dbo.Child (
Id bigint NOT NULL,
ParentId bigint NOT NULL,
TypeId int NOT NULL,
varcharColumn varchar(300) NULL
)
select cast(c.varcharColumn as int)
from dbo.Parent p (nolock)
inner join dbo.Child c (nolock)
on p.Id = c.ParentId
and c.TypeId = 2
where p.TypeId = 13
休憩:
intに変換できない値が原因で、キャストブレークが発生します。この場合:「123-1」。奇妙なことに、キャストされている値が最終結果セットから除外されます。
たとえば、これはゼロの結果を返します
select c.varcharColumn
from dbo.Parent p (nolock)
inner join dbo.Child c (nolock)
on p.Id = c.ParentId
and c.TypeId = 2
where p.TypeId = 13
and c.varcharColumn = '123-1'
クエリプランは、最終的に子テーブルを調べ、where句の前に実際にキャスト関数を適用します。
子テーブルに新しいインデックスを作成することでこれを修正できました(PKスキャンを実行していました)
create index [NCIDX_dbo_Child__TypeId] on dbo.Child (
TypeId
)
include (
ParentId,
varcharColumn
)
親テーブルのwhere句を最初にフィルタリングするようになりました。
追加のインデックスなしでこれを修正する方法はありますか?繰り返しになりますが、スキーマの修正に関連する提案はご遠慮ください。この場合、それは間違いなく適切な修正です。
結果セットをフィルタリングする前にキャストを適用した理由を理解することに主に興味があります。
ありがとう
編集-回答:
アーロンとゴードンの両方に感謝します。15回以上の返信ポイントを獲得した場合は、両方の返信に戻ってきます。
ビューでこのクエリを使用したかったので、Gordonの回答が必要になりました。オフィスの何人かの人々は、最初に小さな結果セットを確実に取得することをより細かく制御することを好むため、caseステートメントの使用に慎重でした(アーロンの答え)が、結局はクエリプランを見てあなたの読み取りをチェックすることになりますカウントします。
繰り返しになりますが、すべての回答に感謝します。