web-dev-qa-db-ja.com

特定の緯度/経度から特定の半径距離内にあるテーブル内の場所を検索します

エリアという名前のテーブルがあり、列には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 +行になります。

enter image description here

インデックス情報は次のとおりです。

enter image description here

100kを超えるレコードで実行すると、このクエリは本当に遅くなります(500ミリ秒かかります)。それを最適化する方法、つまり空間インデックスを使用する方法はありますか?

2
maverick

Q&Aはたくさんあります ここ 。最初のカットとして、「境界ボックス」を使用します。

ANALYZE TABLEおよびOPTIMIZE TABLEは無関係です。

あなたはLattitudeについて言及していますが、そのような列はありません。

pointおよびSPATIALを使用するか、latitudeおよびlongitudeを使用します。それらを混ぜるのはおそらく愚かです。

2
Rick James

GISを使用する

最初、

  1. ptを追加しますST_SRID(ST_Point(longitude,latidue),4326)
  2. 古いlongitude列とlatidue列を削除します。
  3. 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
);
0
Evan Carroll

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を使用する場合、メーターを単位として使用してシステムにポイントを投影します。

テーブルのすべてのポイントを変換する必要があるため、ポイントのテーブルが非常に大きい場合、処理が遅くなる可能性があることに注意してください。

0