最初に1つのインデックスを検索し、次に別のインデックスを検索するようにクエリを最適化する方法


12

衛星データからの2つの地球測定値セットがあり、それぞれに時間フィールド(平均ユリウス日付のmjd)と地理的位置(GeoPoint、空間)があり、2つのセット間の一致が時間のしきい値に一致するように探しています3時間(または.125日)およびそれらの距離は互いに200 km以内です。

テーブルと空間テーブルの両方のmjdフィールドにインデックスを作成しました。

時間の制約に参加するだけで、データベースは8秒で100,000回の一致を計算し、その時間内のすべての100,000回の一致の距離を計算します。クエリは次のようになります。

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

実行された計画は次のとおりです。

mjd制約のみ

並べ替えると、9つの距離が200km未満であったため、一致します。問題は、距離制約を追加して代わりにこれを実行すると、

select top 10 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
and h.GeoPoint.STDistance(m.GeoPoint)<200000
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

それは長い間消えます。明らかに、8秒で100,000回のタイムマッチが見つかり、そのうち9回は200km未満であったため、オプティマイザは次善の方法を試行している必要があります。プランは、距離にフィルターを使用した上記と似ています(推測しています)。

空間定数あり、空間フィルターなし

これで空間インデックスの使用を強制できます:

select top 5 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0 
from L2V5.dbo.header h join L2.dbo.MLS_Header m 
on h.GeoPoint.STDistance(m.GeoPoint)<200000
and h.mjd between m.mjd-.125 and m.mjd+.125 
option( table hint ( h, index(ix_MJD), index(ix_GeoPoint) ), table hint( m, index(ix_MJD) ) )

両方のインデックスを持つ両方の制約

一致するものが5つ見つかるまで3分かかります。

最初にMJDインデックスシークを使用し、次に空間インデックスを使用するようにクエリオプティマイザーに指示する方法(または既に実行していることです)、どのくらい一致するかを予測する方法を教えてください。200 km未満で9の距離で8秒間に100,000の一致を計算できる場合、空間インデックスを追加することで速度が遅くなるのではないでしょうか?

他のヒントやアイデアをありがとう。

編集:ヒントなしで計画がどのように見えるかという質問に答えるために、これ(そしてそれは永遠にかかります):

ヒントなし

1つのテーブルにはほぼ1Mのレコードがあり、もう1つのテーブルには8Mのレコードがあることに言及する価値があるかもしれません


これらのヒントを削除すると、クエリプランはどのようになりますか?
ゼーン

@Zane、投稿を編集し、ヒントなしのクエリプランを追加しました。シークをスキャンに置き換え、タイミングはひどいものになります。
user261963

回答:


6

問題は、空間フィルターが時間フィルターよりもはるかに選択的であると仮定する可能性があります(おそらく空間インデックスを知っていると思われます)。

しかし、200km以内に数百万のレコードがある場合、それは著しく悪化する可能性があります。

200km以内のレコードを検索するように要求しています。これにより、空間的な順序でデータが返されます。時間的に近いレコードを見つけることは、各レコードをチェックすることを意味します。

または、時間ごとにレコードを検索し、時間順に結果を取得します。次に、このリストを半径200 kmの範囲にフィルタリングすることは、それぞれをチェックすることです。

このように2つの範囲でデータをフィルター処理すると、インデックスを使用して2番目のフィルターを適用するのが難しくなります。時間フィルターがより厳しい場合は、空間インデックスを使用しないように指示した方がよい場合があります。

両方が個別に大きく、それらが緊密であるだけである場合、より複雑な問題があり、人々は長い間解決しようとしており、3D(およびそれ以降)をカバーするインデックスによってうまく解決できますスペース。ただし、SQL Serverにはありません。

ごめんなさい。

編集:詳細...

これは、特定の時点をカバーする時間範囲を見つけることに似た問題です。その時点より前に開始するレコードを検索すると、終了時間の順序が乱れます。逆の場合も同様です。電話帳で姓がFで始まる人を探す場合、名がRで始まる人を簡単に見つけることはできません。また、名のインデックスも同じ理由で役に立ちません。最初のインデックスが平等でない場合、その次のインデックスで物事を見つけることは困難です。

日付フィルターを等式フィルター(または一連の等式フィルター)に変更できる場合、空間インデックスは特別な種類のインデックスであり、第2レベルとして使用できないことを除いて、チャンスがあります。複合インデックス。

だから、あなたは厄介な状況に残されている、私は恐れている。:(

編集:試す:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
where h.GeoPoint.STDistance(m.GeoPoint)/1000.0 < 200
option( table hint ( h, index(ix_MJD) ) );

200と比較する前に1000で除算することにより、意図的に可算性を壊していることに注意してください。この作業は、キールックアップで実行する必要があります。

気を付けてください。両方のix_MJDインデックスにGeoPointとTimeを含めることで、ルックアップ(およびヒント)の必要性を回避できます。それは確かにクエリプランから熱の一部を取り除きます。


変更されるかどうかはわかりませんが、時間フィルターの方がはるかに選択的です。
user261963

OK。だから、時間的に一致するすべての行を見つけて、インデックスなしで各場所をチェックすることは受け入れられますか?
ロブファーリー

...そのため、プランは元のプランのように見えますが、余分な述語またはフィルターがあります。
ロブファーリー

簡単な編集でいくつかの変更を提案しました。mについて暗示する必要はなく、hだけです。1/8を追加するものを交換できる場合は、小さいテーブルの列を変更し、それらの値を使用して大きいテーブルをシークすることを確認するためにも役立ちます。hが8Mでmが1Mの場合、BETWEEN述部をそのままにして、hだけのヒントを残します。逆の場合は、述語とヒントを変更します(ただし、ヒントを変更するよりも、それらの列をインデックスに追加することをお勧めします)。
ロブファーリー

すべてのテーブルヒントを取り出すことは、私がmの間でhを行い、その逆ではない限り、最終的には最もうまくいくようです。クエリはGeoPointインデックスを使用しなくなりましたが、とにかくそれらを効率的に使用していませんでした。GeoPoint列をMJDインデックスに含めましたが、これは非常に役立ちました。select top 10000 h.Time, m.Time, m.GeoPoint.STDistance(h.GeoPoint), h.mjd-m.mjd from L2V5.dbo.header h join L2.dbo.MLS_Header m on m.GeoPoint.STDistance(h.GeoPoint)<200000 and m.mjd between h.mjd-.125 and h.mjd+.125 order by h.mjd
user261963
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.