残念ながら、 ST_Distance() < threshold
sargable
ではありません 検索基準。このクエリを満たすには、MySQLはテーブル内のすべての行の関数の値を計算し、それをしきい値と比較する必要があります。したがって、全表スキャン(または全表スキャン)を実行する必要があります。
インデックスを利用してこのクエリを高速化するには、バウンディングボックス基準が必要になります。クエリははるかに複雑ですが、はるかに高速です。ジオメトリのx/yポイントが緯度/経度を度で表すとすると、そのクエリは次のようになります。
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)
これはどのように作動しますか?一つには、 MbrContains(バウンド、アイテム) 関数はです sargable 。別のこととして、大きな醜いコンキャットアイテムは、境界長方形の南西から北東の角に対角線を生成します。データポイントと半径10マイルを使用すると、次のようになります。
LINESTRING(37.8785 -94.2564,38.1684 -93.8884)
GeomFromText()
を使用する場合 MbrContains()
の最初の引数でのその対角線のレンダリング 境界矩形として機能します。 MbrContains()
その後、気の利いた四分木ジオメトリインデックスを活用できます。
第三に、ST_Distance()
、MySQLでは、大円の緯度と経度の計算を処理しません。 ( PostgreSQL
より包括的なST_Distance() < 10.0
lng/latポイントで何か奇妙なことをします。
このクエリが生成する結果には1つの欠陥があります。指定された半径内だけでなく、バウンディングボックス内のすべてのポイントを返します。これは、別の距離計算で解決できます。私はこれをすべて
注 :GPS解像度の緯度と経度の場合、32ビットのFLOAT
データには十分な精度があります。 DOUBLE
MySQLのgeo拡張機能が使用するものです。度で作業している場合、小数点以下5桁以上はGPSの精度を超えています。 DECIMAL()
緯度/経度座標の理想的なデータ型ではありません。