Cara mengoptimalkan kueri sehingga mencari pada satu indeks terlebih dahulu, lalu indeks lain setelah itu

12

Saya memiliki dua set pengukuran bumi dari data satelit, masing-masing dengan bidang waktu (mjd untuk tanggal julian rata-rata) dan posisi geografi (GeoPoint, spasi) dan saya mencari kebetulan di antara dua set sehingga waktu mereka cocok dengan ambang batas 3 jam (atau 0,125 hari) dan jaraknya dalam jarak 200 km.

Saya telah membuat indeks untuk bidang mjd di kedua tabel dan tabel spasial.

Ketika saya baru saja bergabung dengan batasan waktu, basis data menghitung 100.000 kecocokan dalam 8 detik dan menghitung jarak untuk semua 100.000 kecocokan pada waktu itu. Kueri terlihat seperti ini:

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) ) )

Dan rencana yang dijalankan adalah:

Hanya kendala mjd

Saat disortir, 9 jaraknya berada di bawah 200km, jadi ada yang cocok. Masalahnya adalah, ketika saya menambahkan batasan jarak dan menjalankan ini sebagai gantinya,

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) ) )

itu hilang untuk waktu yang lama. Jelas, dalam 8 detik, dapat menemukan 100.000 pertandingan yang sesuai, 9 di antaranya berada di bawah 200 km, sehingga pengoptimal harus mencoba sesuatu yang kurang optimal. Rencananya terlihat mirip dengan di atas dengan filter pada jarak (saya menduga).

dengan batasan spasial, tanpa filter spasial

Saya bisa memaksakan penggunaan indeks spasial dengan ini:

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) ) )

kedua kendala dengan kedua indeks

yang kemudian membutuhkan 3 menit untuk menemukan 5 pertandingan.

Bagaimana saya memberi tahu pengoptimal kueri untuk menggunakan pencarian indeks MJD pertama, dan kemudian indeks spasial kedua (atau apakah itu yang sudah dilakukannya) dan apakah ada cara saya dapat membantu dengan memberi tahu berapa banyak kecocokan yang diharapkan? Jika ia dapat menghitung 100.000 pertandingan dengan jarak dalam 8 detik yang memiliki 9 di bawah 200km, bukankah seharusnya penambahan indeks spasial membuatnya lebih cepat, bukan lebih lambat?

Terima kasih atas kiat atau ide lain.

EDIT: Untuk menjawab pertanyaan seperti apa rencana itu tanpa petunjuk, ini (dan ini akan berlangsung selamanya):

tidak ada petunjuk

Mungkin juga layak disebutkan bahwa ada hampir 1 juta catatan di satu meja dan 8 juta di yang lain

pengguna261963
sumber
Seperti apa rencana kueri Anda jika Anda menghapus petunjuk itu?
Zane
@ Zane, saya mengedit posting dan menambahkan rencana permintaan no-hint. Mengganti pencarian dengan pemindaian dan waktunya tidak tepat.
user261963

Jawaban:

6

Masalahnya adalah bahwa ia mungkin (dan mengetahui indeks spasial, mungkin akan) menganggap bahwa filter spasial akan jauh lebih selektif daripada filter waktu.

Tetapi jika Anda memiliki beberapa juta catatan dalam jarak 200 km, maka itu bisa menjadi jauh lebih buruk.

Anda memintanya untuk menemukan catatan dalam jarak 200 km, yang mengembalikan data yang dipesan oleh beberapa tata ruang. Menemukan catatan di sana yang mendekati waktu berarti memeriksa masing-masing.

Atau Anda akan menemukan catatan berdasarkan waktu, dan Anda mendapatkan hasil dalam urutan waktu. Kemudian, memfilter daftar ini ke radius 200 km adalah masalah memeriksa masing-masing.

Jika Anda memfilter data dalam dua rentang seperti ini, menjadi sulit untuk menerapkan filter kedua menggunakan indeks. Anda mungkin lebih baik mengatakannya untuk tidak menggunakan indeks spasial jika filter waktu lebih ketat.

Jika keduanya besar secara individual, dan itu hanya bersama-sama bahwa mereka ketat, maka Anda memiliki masalah yang lebih kompleks, yang orang telah mencoba untuk memecahkannya untuk waktu yang lama, dan yang bisa diselesaikan dengan baik oleh indeks yang mencakup 3D (dan seterusnya) ruang. Kecuali SQL Server tidak memilikinya.

Maaf.

Edit: info lebih lanjut ...

Ini adalah masalah yang mirip dengan menemukan rentang waktu yang mencakup titik waktu tertentu. Saat Anda mencari catatan yang dimulai sebelum titik itu, Anda kemudian memiliki kekacauan akhir zaman yang tidak teratur - dan sebaliknya. Jika Anda mencari orang-orang di buku telepon yang nama keluarganya dimulai dengan F, Anda tidak bisa berharap menemukan orang-orang yang nama depannya dimulai dengan R dengan sangat mudah. Dan indeks pada nama depan juga tidak membantu karena alasan yang sama. Menemukan hal-hal dalam indeks berikutnya sulit ketika indeks pertama Anda bukan persamaan.

Sekarang, jika Anda dapat mengubah filter tanggal menjadi filter kesetaraan (atau serangkaian filter kesetaraan), maka Anda dapat mengambil risiko, kecuali bahwa indeks spasial adalah jenis indeks khusus dan tidak dapat digunakan sebagai tingkat kedua dalam indeks komposit.

Jadi Anda ditinggal dengan situasi yang canggung, saya khawatir. :(

Sunting: Coba:

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) ) );

Perhatikan bahwa saya sengaja melanggar sargability dengan membaginya dengan 1000 sebelum membandingkan dengan 200. Saya ingin pekerjaan ini dilakukan dalam Pencarian Kunci.

Pikiran Anda, Anda bisa menghindari kebutuhan untuk pencarian (dan petunjuk) dengan TERMASUK GeoPoint dan Waktu di kedua indeks ix_MJD. Itu pasti akan mengambil beberapa panas dari rencana permintaan.

Rob Farley
sumber
Saya tidak tahu apakah itu mengubah apa pun, tetapi filter waktu jauh lebih selektif.
user261963
Baik. Jadi apakah dapat diterima untuk menemukan semua baris yang cocok dengan waktu dan kemudian memeriksa setiap lokasi tanpa indeks?
Rob Farley
... jadi rencananya terlihat seperti aslinya, tetapi memiliki predikat atau filter tambahan.
Rob Farley
Menyarankan beberapa perubahan dengan edit cepat. Anda tidak perlu memberi petunjuk tentang m, h. Meskipun jika Anda dapat menukar yang Anda tambahkan 1/8, untuk memastikan Anda memodifikasi kolom dari tabel yang lebih kecil dan menggunakan nilai-nilai itu untuk mencari yang lebih besar, itu juga akan membantu. Jika h adalah 8M dan m adalah 1M, tinggalkan predikat ANTARA, dan berikan petunjuk untuk h saja. Jika sebaliknya, ubah predikat dan petunjuk Anda (tetapi lebih baik daripada mengubah petunjuk itu dengan menambahkan kolom-kolom itu ke indeks Anda).
Rob Farley
Mengeluarkan semua petunjuk tabel tampaknya bekerja paling baik pada akhirnya, selama saya melakukannya antara m dan bukan sebaliknya. Kueri tidak lagi menggunakan indeks GeoPoint sama sekali, tetapi toh tidak menggunakannya dengan efisien. Saya memasukkan kolom GeoPoint ke indeks MJD dan itu banyak membantu. 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