このクエリを満たすことができるインデックスはありません。これは実際には、2 つのインデックスを作成し、2 つのクエリを実行してから、結果を UNION するのが最善であることを意味します...
1) InputBegin でインデックスを
作成する 2) InputEnd で別のインデックスを作成する
3) 次のクエリを実行する
SELECT * FROM yourTable WHERE InputEnd < ExclusionPeriodStart
UNION ALL
SELECT * FROM yourTable WHERE InputBegin > ExclusionPeriodEnd
最初のクエリは、InputEnd インデックスで範囲シークを使用できます。2 番目のクエリでも範囲シークを使用できますが、別のインデックスに対して行います。
クエリを分離することで、2 つの異なる要件が互いに干渉せず、最適なインデックスを使用できます。
また、(データを理解することで) 結果に重複がないこともわかっています (終了する前にレコードを開始することはできないため、両方のクエリにレコードが表示されることはありません)。これはUNION ALL
、より遅い の代わりに を使用できることを意味しますUNION
。
私の知る限り、このクエリをこれよりも高速に実行する方法はありません。(5m レコードでは、小さなデータセットでテーブル全体をスキャンする方がおそらく高速です。)
編集:その答えは、固定範囲内に表示されないすべてのレコードを検索しようとしていることを前提としています。すべてのレコードを他のすべてのレコードに対してチェックしたい場合は、別のアプローチが必要です...
すべてのオーバーラップをチェックするのはコストがかかります。また、これらの 4 つの範囲がある場合、どれを削除するかを考え出すことは不可能です...
1 -->--> 4
3 -->--> 6
5 -->--> 8
7 -->--> 9
範囲 1 と 3、または範囲 2 と 4 を削除する必要がありますか?
できることは、別の範囲が重複しているすべての範囲を見つけることです。
そして、A が B とオーバーラップし、B が A とオーバーラップすることを見つけたくないのです。
SELECT
*
FROM
yourTable AS first_range
INNER JOIN
yourTable AS second_range
ON second_range.start_date >= first_range.start_date
AND second_range.start_date <= first_range.end_date
これは必然的にテーブル全体をスキャンして first_range を探します。ただし、2 番目の範囲の start_date のみを確認するため、衝突に対して start_date インデックスで範囲シークを使用できます。
EDIT2:または、最初の答えの反対が必要ですか?
設定された範囲と衝突するすべての範囲が必要な場合は、同じアプローチの変更が機能します。
SELECT * FROM yourTable WHERE InputEnd >= ExclusionPeriodStart
INTERSECT
SELECT * FROM yourTable WHERE InputBegin <= ExclusionPeriodEnd
しかし、これは素晴らしいことではないかもしれません。query1 のテーブルのパーセンテージを取得し、それをテーブルの残りのほぼすべてと交差させます。代わりに、単純なアプローチに頼ることができますが、最適化を追加します...
SELECT
*
FROM
yourTable
WHERE
InputStart <= ExclusionPeriodEnd
AND InputEnd >= ExclusionPeriodStart
WHERE 句の最初の条件は、範囲シークで解決できます。次に、結果のすべてのレコードをスキャンして、2 番目の条件をテストします。では、スキャンが必要な範囲を減らすことはできますか(currently (start of table) -> (ExclusionPeriodEnd))
。
追加の情報が 1 つわかっていれば可能です: 任意の 1 つの範囲の最大長...
SELECT
*
FROM
yourTable
WHERE
InputStart <= ExclusionPeriodEnd
AND InputStart >= ExclusionPeriodStart - (maximumLength)
AND InputEnd >= ExclusionPeriodStart
ここで、最初の 2 つの条件が範囲シークを形成し、最後の条件をスキャンするためのはるかに小さなデータ セットを提供します。
ただし、最大長はどうやってわかりますか?テーブル全体をスキャンすることもできますが、それは最適化における自滅的な試みです。
代わりに、計算フィールドにインデックスを付けることができます。範囲の最大長を与える計算。 SELECT MAX(calculatedField) FROM yourTable
次に、テーブル全体のスキャンを回避します。または、トリガーを使用して追跡することもできます。どちらが INSERTS の場合は問題ありませんが、DELETE がある場合は少し面倒です (最長の範囲を削除した場合、新しい最長の範囲を見つけるためにテーブル全体を再度スキャンしますか? おそらくそうではなく、古い最大長を維持したくなるかもしれません)代わりは)。