3

次のように、charindexのサブストリングを選択するステートメントがあります。

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE 
CHARINDEX('ABC', StringField) > 5

上記のステートメントをselectクエリで実行すると、結果は問題なく返されます。スキーマにバインドされたインデックス付きビューで上記のステートメントを実行すると、次のエラーが発生します。

Invalid length parameter passed to the LEFT or SUBSTRING function

この問題を解決するために、負の値の可能性を排除するために、CharIndexの最大値と0を取得する関数を記述します。しかし、where句がselectステートメントを除外しない理由を誰かが知っていますか?

4

2 に答える 2

2

クエリの舞台裏での操作の順序は保証されていないためです。

実行プランをチェックすると、両方のチェックが並行して実行されていることがわかると思います。これは、どちらの操作もインデックスを使用できないためです。

SQLはとにかくそのフィールドのすべての行をメモリにロードする必要があるため、両方の基準で同時に処理します。

WITH (MAXDOP(1))クエリのヒントとして、問題が表示されないかどうかを確認するか、副選択を実行して実行順序を強制することができます。

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
FROM (
      SELECT Stringfield 
      FROM Table 
      WHERE CHARINDEX('ABC', StringField) > 5
      ) as [X]

フィールドが数値を使用しているかどうかを確認しているときに同様の問題が発生PATINDEXし、ビューの列の1intつがこれを-に変換していました-フィルターがSARG可能ではなかったため、エンジンがすべての行を変換していたため、変換エラーが発生しました。

于 2012-02-24T16:57:35.270 に答える
1

これは醜い回避策ですが、おそらく次のようなことを行うことができます。

DECLARE @x TABLE(StringField VARCHAR(32));

INSERT @x SELECT 'ABC'
UNION ALL SELECT 'A'
UNION ALL SELECT 'AAAAAAAABC';

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

SELECT SUBSTRING(StringField,
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 1 END,
    CHARINDEX('ABC', StringField) - 
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 0 END)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

両方の収量:

---
AAA

しかし、私は後者があなたの見解で許可されると思います。醜いですが、残念ながら、最初にフィルタリングされたデータを#tempテーブルにダンプしない限り(またはMAXDOP問題が確実に削除されるかどうかを確認しようとしない限り)、処理の順序をあまり制御できません。

もう1つのアイデアは、計算列をテーブルに配置することです(ただし、インデックス付きビューを作成しようとしている場合に役立つかどうかはわかりませんが、まだ問題がある可能性があります)。または、インデックス付きビューの代わりに、その式でフィルター処理されたインデックスを使用します。インデックス付きビューの目的と使用しているSQLServerのバージョンがわかっている場合は、いくつかの「解決策」が存在する可能性があります。

于 2012-02-24T17:17:38.090 に答える