クライアントからのカスタム データへのアダプタを作成しています。新しいインデックスを提案することはできますが、スキーマを変更したり、テーブルの値を変更したりすることはできません。このアプローチは、CTE を使用してカスタム データを結合し、再フォーマットして、列名、列挙値などを使用することです。データが再フォーマットされると、標準の CTE を追加して、標準の分析を実行できるクエリをそれから作成できます。
再フォーマットの結果の一部の値は、LEFT JOIN が一致しなかったため、または実際には NULL であるデータの値が原因で NULL になります。
私の仕事は、多くのフィールドで NULL をデフォルト値に置き換え、クエリに WHERE 句を挿入できるようにすることです。現在、デフォルト値の処理には ISNULL 呼び出しまたは CASE ステートメントが使用されています。現在、WHERE 条件がヒットするまでに、この置換は既に実行されているため、クエリ ビルダーにアクセスできるエンド ユーザーは、既定値である可能性のある値をフィルター処理できます。フィルタ値がデフォルト値の場合、デフォルト値に置き換えられた NULL 値を持つレコードを選択する必要があります。
問題は、再フォーマット式として myField = ISNULL(myField, 'MyDefault') があり、後でタマネギの外層 (後の CTE) に WHERE myField = 'MyDefault' がある場合、この where 句はsargable: クエリ オプティマイザは myField のインデックスを選択しません。
私が思いつく部分的な解決策は、内部 CTE で NULL 置換を行わず、WHERE 句を挿入する CTE を作成し、すべての NULL 置換を実行する外部 CTE を作成することです。このようなクエリでは、インデックスを使用できます。(私はこれを確認しました。)しかし、where 句は、デフォルト値に対する値のテストでも NULL 値を持つレコードを取得することを期待できなくなりました。これは、その置換がまだ行われていないためです。
null 置換を実行し、SARGABLE where フィルターを許可し、NULL 値をデフォルト値を保持しているかのようにフィルター処理する方法はありますか?
問題のサイズに関する注意: 典型的な例では、600 万レコードのテーブルを 700 万レコードのテーブルに結合し、1200 万のレコードを作成する多対多のリレーションシップを使用します。フィルターが SARGABLE の場合、クエリには約 10 秒かかります。SARGABLE でない場合、1 台のマシンで 10 分以上、より高速なマシンでは 3 分以上かかります。
選択したソリューションに関するコメント:
フィールドを NULL または非 NULL と ISNULL またはその他のサージ不可関数なしで比較できるようにするための交差の巧妙な使用は、従来のクエリへの変更を最小限に抑えてコードに組み込むことができます。
コメント 2: ケースの欠落
次の 6 つのケースがあります。
- 選択された値は null ではなく、デフォルトと等しくなく、フィルタ値と一致しません。除外する必要があります。
- 選択された値は null ではなく、デフォルトと等しくなく、フィルター値と一致します。含める必要があります。
- 選択された値は null ではなく、デフォルト値と等しく、フィルタ値と一致しません。除外する必要があります。
- 選択された値は null ではなく、DOES はデフォルト値と等しく、DOES はフィルター値と一致します。含める必要があります。
- 選択された値は null であり、フィルタ値はデフォルトではありません。除外する必要があります。
- 選択された値は null で、フィルタ値はデフォルトです。含める必要があります。
ケース 4 は、提供されたソリューションを使用しても機能しません。選択したフィールドは null ではないため、交差部分の前半には非 null 値を持つレコードがあります。しかし、交差点の後半では、NULLIF ステートメントによって null 値を持つレコードが作成されています。交差はゼロ レコードを生成します。レコードは拒否されます。このケースを処理するソリューションをまだ探しています。とても近い...
更新ソリューション:
修正があります。[County Name] に適合していて、デフォルト値が「不明」であるとします...
where EXISTS (
select [County Name]
intersect
(select NULLIF('User selected county name', 'Unknown') union select 'User selected county name')
)