ここで非常に奇妙なことが起こっています。
次のようなクエリがあります。
SELECT CAST(FT.DOP AS SMALLINT) FROM TRACKING_DATA WHERE date > @mydate and identifier = 0000000000
生のクエリとして実行すると、データは正常に返されます。
Where句を変更するストアドプロシージャに配置すると、このエラーがスローされます。
Msg 244, Level 16, State 2, Procedure myprocedure, Line 107 [Batch Start Line 2]
The conversion of the varchar value '58629' overflowed an INT2 column. Use a larger integer column.
だからここに奇妙です。このようなクエリでwhere句のすべての可能なデータを調べます。
SELECT DISTINCT DOP FROM TRACKING_DATA where identifier = 000000000000
そして
SELECT DISTINCT CAST(DOP AS smallint) FROM TRACKING_DATA where identifier = 000000000000
そして、これは私が取り戻すものです。
17
12
9
19
8
14
6
16
11
13
7
10
0
18
5
15
4
SMALLINT
に対してリモートで大きすぎるものはどこにもありません。だから私は思った、多分それは印刷できないASCII文字です。しかし、何も見つけることができません。
今は少し困惑しています。それは生のクエリとしてfindを実行し、プロシージャとして爆発し、whereが有効であることに基づいてすべての可能なデータを爆発させます。私の唯一の疑いは、クエリプランがフィルタリングで奇妙なことをしている、またはプロシージャとして実行したときに別の検証で実行していることです。
これらのエラーを回避するには、インデックス作成に依存せず、代わりにクエリを記述してこの状況を防ぐ方がよいでしょう。 SQL Server 2012を使用しているので、1つのオプションはTRY_CASTを使用することです。
SELECT TRY_CAST(FT.DOP AS SMALLINT)
FROM TRACKING_DATA
WHERE date > @mydate and identifier = 0000000000;
これにより、varcharからsmallintへの変換に失敗した値に対してNULL
が選択されます。しかし、そのような結果がないこと、またはアプリケーションがNULL
の結果を処理できることがわかっている限り、問題はありません。
それで、それはそれが使用することを決め続けたいまいましいクエリ計画でした。
爆発している値はテーブルに存在していましたが(それはあり得ないはずですが、それは別の問題です)、完全に異なる識別子に関連付けられていました。
問題のクエリはclustered seek
date
をカバーするがidentifier
をカバーしないインデックスでこれを行うと、ENTIREテーブルがスキャンされましたが、これは多くの理由で間違っています。
where
句に適切なインデックスを追加しました。日付の後に進む前に識別子でフィルター処理を行うため、この手順は問題なく終了しています。私は統計の前後を取得できればいいのにと思っていますが、今でも実行速度が速いと確信しています。
あなたは明らかに異なるクエリプランを取得しており、キャストはwhere句によってフィルターで除外された値に対して試行されています。理由を理解しようとはしません。原因が何であれ、後で別の理由で明らかに発生する可能性があります。フィルタリングに依存することは信頼できません。
すべきことは、インデックス、ヒント、統計に関係なく失敗しないクエリを作成することです。
これには3つの方法があると思います。
一時テーブル/テーブル変数を使用します。
declare @result table (dop varchar);
Insert into @result
SELECT FT.DOP FROM TRACKING_DATA
WHERE date > @mydate and identifier = 0000000000
SELECT cast(dop as SMALLINT) dop from @result
Caseステートメントを使用します。
SELECT CAST(case when FT.DOP like '%[^0-9]%' then null else ft.dop end AS SMALLINT)
FROM TRACKING_DATA
WHERE date > @mydate and identifier = 0000000000
代わりに、キャストのtry_castを使用します。
SELECT try_CAST(FT.DOP AS SMALLINT)
FROM TRACKING_DATA
WHERE date > @mydate and identifier = 0000000000
個人的には、できれば3をお勧めします。