エリアという名前のテーブルがあり、列にはID、名前、緯度、経度、位置があります。位置列はMySQLのPOINTタイプで、緯度と経度の値があります。
特定の緯度、経度、つまり(28.638753、77.073803)から25キロメートル以内のエリアを取得し、このポイントへの近さに基づいてそれらを順序付けるために、Googleの推奨 here として次のクエリを使用しています。
SELECT id, name, ( 6371 * acos( cos( radians(28.638753) ) * cos( radians( Lattitude ) ) * cos( radians( Longitude ) - radians(77.073803) ) + sin( radians(28.638753) ) * sin( radians( Lattitude ) ) ) ) AS distance
FROM areas
HAVING distance < 25
ORDER BY distance asc;
テーブルは次のとおりです。
CREATE TABLE `areas` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(50) NOT NULL,
`Lattitude` decimal(18,6) DEFAULT NULL,
`Longitude` decimal(18,6) DEFAULT NULL,
`position` point NOT NULL,
PRIMARY KEY (`ID`),
SPATIAL KEY `sx_areas_position` (`position`)
)
説明クエリは次のようになります。テストデータであるため、rows = 21750であることに注意してください。本番環境の実際のデータは100k +行になります。
インデックス情報は次のとおりです。
100kを超えるレコードで実行すると、このクエリは本当に遅くなります(500ミリ秒かかります)。それを最適化する方法、つまり空間インデックスを使用する方法はありますか?
Q&Aはたくさんあります ここ 。最初のカットとして、「境界ボックス」を使用します。
ANALYZE TABLE
およびOPTIMIZE TABLE
は無関係です。
あなたはLattitude
について言及していますが、そのような列はありません。
point
およびSPATIAL
を使用するか、latitude
およびlongitude
を使用します。それらを混ぜるのはおそらく愚かです。
最初、
pt
を追加しますST_SRID(ST_Point(longitude,latidue),4326)
longitude
列とlatidue
列を削除します。CREATE SPATIAL INDEX spatidx ON areas (pt);
次に、このようなことをします
SELECT ST_AsText(pt)
FROM areas
WHERE ST_Within(
ST_Buffer( ST_SRID(ST_Point(77.073803,28.638753), 4326), 25000 ),
pt
);
MySQLの空間機能を使用しないのはなぜですか?
それはそのようになります:
SELECT *
FROM areas
WHERE ST_Distance(ST_Transform(position, [SRID]), ST_Transform(ST_GeomFromText('Point(28.638753 77.073803)', 4326)), [SRID]) < 25000
ST_GeomFromText()は、緯度/経度座標で空間内にポイントを作成します。 [SRID]は、そのポイントを配置するために使用される地理システムを表すEPSGコードです。 4326は、WGS84データムを使用する従来の非投影地理システムです(GPSはこのシステムで動作します)。
次に、テーブル内のすべてのポイントで特定の距離を確認しますが、メートル単位の[SRID]で確認する必要があります。そのためには、多かれ少なかれローカルな投影法を使用する必要があります。ケベック州東部では、32198または32188をよく使用します。 ST_Transform()は、適切なSRIDを使用する場合、メーターを単位として使用してシステムにポイントを投影します。
テーブルのすべてのポイントを変換する必要があるため、ポイントのテーブルが非常に大きい場合、処理が遅くなる可能性があることに注意してください。