11

各ポイントの名前とともに緯度/経度の座標を格納するために、次の MySQL テーブルを作成しました。

CREATE TABLE `points` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL,
  `location` point NOT NULL,
  PRIMARY KEY (`id`),
  SPATIAL KEY `location` (`location`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

私はクエリしようとしています:

  • 特定のポイントから半径nマイル以内のすべてのポイント。
  • 指定されたポイントから返された各ポイントの距離

私が見つけたすべての例は、半径ではなく最小外接矩形 (MBR) の使用を参照しています。テーブルには約 100 万点が含まれているため、これは可能な限り効率的に行う必要があります。

4

3 に答える 3

7

MySQL 5.7 以降の場合

次の単純なテーブルがあるとします。

create table example (
  id bigint not null auto_increment primary key,
  lnglat point not null
);

create spatial index example_lnglat 
    on example (lnglat);

以下の簡単なデータで、

insert into example (lnglat) 
values
(point(-2.990435, 53.409246)),
(point(-2.990037, 53.409471)),
(point(-2.989736, 53.409676)),
(point(-2.989554, 53.409797)),
(point(-2.989350, 53.409906)),
(point(-2.989178, 53.410085)),
(point(-2.988739, 53.410309)),
(point(-2.985874, 53.412656)),
(point(-2.758019, 53.635928));

次の st 関数の組み合わせを使用して、別のポイントの特定の範囲内のポイントを取得します (注: ポリゴン内を検索する必要があります)。

set @px = -2.990497;
set @py = 53.410943;
set @range = 150; -- meters
set @rangeKm = @range / 1000;

set @search_area = st_makeEnvelope (
  point((@px + @rangeKm / 111), (@py + @rangeKm / 111)),
  point((@px - @rangeKm / 111), (@py - @rangeKm / 111))
);

select id, 
       st_x(lnglat) lng, 
       st_y(lnglat) lat,
       st_distance_sphere(point(@px, @py), lnglat) as distance
  from example
 where st_contains(@search_area, lnglat);

結果として、次のように表示されます。

3   -2.989736   53.409676   149.64084252776277
4   -2.989554   53.409797   141.93232714661812
5   -2.98935    53.409906   138.11516275402533
6   -2.989178   53.410085   129.40289289527473

距離の参考として、制約を削除すると、テスト ポイントの結果は次のようになります。

1   -2.990435   53.409246   188.7421181457556
2   -2.990037   53.409471   166.49406509160158
3   -2.989736   53.409676   149.64084252776277
4   -2.989554   53.409797   141.93232714661812
5   -2.98935    53.409906   138.11516275402533
6   -2.989178   53.410085   129.40289289527473
7   -2.988739   53.410309   136.1875540498202
8   -2.985874   53.412656   360.78532732013963
9   -2.758019   53.635928   29360.27797292756

注1:フィールドはlnglatと呼ばれます。これは、ポイントを(x、y)と考える場合の正しい順序であり、ほとんどの関数(ポイントなど)がパラメーターを受け入れる順序でもあるためです。

注 2 : 円を使用する場合、空間インデックスを実際に利用することはできません。また、ポイント フィールドは null を受け入れるように設定できますが、null 許容の場合は空間インデックスでインデックス付けできないことにも注意してください (インデックス内のすべてのフィールドは null 以外である必要があります)。

注 3 : st_buffer は (ドキュメントによると) このユース ケースには不適切であると見なされています。

注 4 : 上記の関数 (特に st_distance_sphere) は高速であると記載されていますが、必ずしも超正確であるとは限りません。データが非常に機密性の高い場合は、検索に少し余裕を持たせて、結果セットを微調整します

于 2016-09-13T11:25:51.790 に答える
2

Radius は効率的にインデックス可能ではありません。境界長方形を使用して、おそらく探しているポイントをすばやく取得してから、半径の外側のポイントをフィルタリングする必要があります。

于 2010-03-09T18:36:57.853 に答える
1

半径のある円の内側の1点に対してそれを行いました

SELECT 
    *
FROM 
    `locator`
WHERE
    SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`
于 2014-04-23T05:11:03.160 に答える