Sayangnya ST_Distance() < threshold
bukan seorang sargable
kriteria pencarian. Untuk memenuhi permintaan ini, MySQL harus menghitung nilai fungsi untuk setiap baris dalam tabel, dan kemudian membandingkannya dengan ambang batas. Jadi ia harus melakukan pemindaian tabel penuh (atau mungkin pemindaian indeks penuh).
Untuk mengeksploitasi indeks untuk mempercepat kueri ini, Anda akan memerlukan kriteria kotak pembatas. Permintaannya jauh lebih rumit tetapi juga jauh lebih cepat. Dengan asumsi titik x/y dalam geometri Anda mewakili garis lintang/garis bujur dalam derajat, kueri tersebut mungkin terlihat seperti ini:
set @latpoint = 38.0234332;
set @lngpoint = -94.0724223;
set @r = 10.0; /* ten mile radius */
set @units=69.0; /* 69 statute miles per degree */
SELECT AsText(geo)
FROM markers
WHERE MbrContains(GeomFromText(
CONCAT('LINESTRING(', @latpoint-(@r/@units),' ',
@lngpoint-(@r /(@units* COS(RADIANS(@latpoint)))),
',',
@latpoint+(@r/@units) ,' ',
@lngpoint+(@r /(@units * COS(RADIANS(@latpoint)))),
')')),
geo)
Bagaimana cara kerjanya? Untuk satu hal, MbrContains( terikat, barang) fungsi adalah sargable . Untuk hal lain, item concat jelek besar menghasilkan garis diagonal dari barat daya ke sudut timur laut dari persegi panjang pembatas. Menggunakan titik data Anda dan radius sepuluh mil akan terlihat seperti ini.
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)
Saat Anda menggunakan GeomFromText()
rendering garis diagonal dalam argumen pertama ke MbrContains()
itu berfungsi sebagai persegi panjang pembatas. MbrContains()
kemudian dapat mengeksploitasi indeks geometri quadtree yang bagus.
Ketiga, ST_Distance()
, di MySQL, tidak menangani perhitungan garis lintang dan garis bujur yang bagus. (PostgreSQL
memiliki ekstensi GIS
yang lebih komprehensif .) MySQL sama bodohnya dengan flapjack di flatland. Ini mengasumsikan poin Anda dalam objek geometris Anda diwakili dalam geometri planar. Jadi ST_Distance() < 10.0
dengan lng/lat poin melakukan sesuatu yang aneh.
Ada satu kekurangan dalam hasil yang dihasilkan kueri ini; itu mengembalikan semua titik di kotak pembatas, tidak hanya dalam radius yang ditentukan. Itu bisa dipecahkan dengan perhitungan jarak terpisah. Saya telah menulis semua ini dalam beberapa detail di sini .
Catatan :Untuk garis lintang dan garis bujur resolusi GPS, FLOAT
32 32-bit data memiliki presisi yang cukup. DOUBLE
adalah apa yang digunakan ekstensi geografis MySQL. Saat Anda bekerja dalam derajat, lebih dari lima tempat setelah titik desimal berada di luar ketepatan GPS. DECIMAL()
bukan tipe data ideal untuk koordinat lat/lng.