Frage

Ich habe die folgende MySQL -Tabelle erstellt, um für jeden Punkt Breiten-/Längengrad -Koordinaten zusammen mit einem Namen zu speichern:

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;

Ich versuche zu fragen:

  • alle Punkte innerhalb eines n Meilenradius eines bestimmten Punktes;
  • Der Abstand jedes zurückgegebenen Punkts vom angegebenen Punkt

Alle Beispiele, die ich gefunden habe, beziehen sich eher auf ein minimales Begrenzungsrechteck (MBR) als einen Radius. Die Tabelle enthält ungefähr 1 Million Punkte, daher muss dieser Bedarf so effizient wie möglich sein.

War es hilfreich?

Lösung 2

Vielen Dank für Ihre Antworten.

Ich fand schließlich die Lösung bei http://www.movable-type.co.uk/scripts/latlong-db.html.

Andere Tipps

Für MySQL 5.7+

Angesichts der Tatsache, dass wir die folgende einfache Tabelle haben,

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

create spatial index example_lnglat 
    on example (lnglat);

Mit den folgenden einfachen Daten,,

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));

Sie würden die Punkte innerhalb eines bestimmten Bereichs eines anderen Punktes erhalten (Hinweis: Wir müssen in einem Polygon suchen) mit der folgenden Kombination von ST -Funktionen:

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);

Infolgedessen sollten Sie so etwas sehen:

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

Als Referenz auf die Entfernung sieht das Ergebnis für den Testpunkt so aus:

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

Anmerkung 1: Das Feld wird als LNGlat bezeichnet, da dies die richtige Reihenfolge ist, wenn Sie Punkte als (x, y) betrachten und auch die Reihenfolge für die meisten Funktionen (wie Punkt) akzeptieren, akzeptieren den Parameter

Anmerkung 2: Sie können nicht die räumlichen Indizes nutzen, wenn Sie Kreise verwenden. Beachten Sie auch, dass das Punktfeld so eingestellt werden kann, dass NULL angenommen wird, aber räumliche Indizes es nicht indexieren können, wenn es nullbar ist (alle Felder im Index müssen nicht null sein).

Notiz 3: ST_Buffer wird (durch die Dokumentation) als schlecht für diesen Anwendungsfall betrachtet

Anmerkung 4: Die obigen Funktionen (insbesondere st_distance_Sphere) sind so schnell, aber nicht unbedingt super genau dokumentiert. Wenn Ihre Daten der Suche ein wenig spielerisch ein wenig spielerisch fügen und dem Ergebnissatz eine Feinabstimmung durchführen

Radius ist nicht effizient indexierbar. Sie sollten das Begrenzungsrechteck verwenden, um schnell die Punkte zu erhalten, nach denen Sie wahrscheinlich suchen, und dann Punkte außerhalb des Radius filtern.

Ich habe das für einen Punkt im Kreis mit Radius getan

SELECT 
    *
FROM 
    `locator`
WHERE
    SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`

Details und eine weitere Beispielabfrage hier http://dexxtr.com/post/83498801191/how-to-determin-point-inside-circle-using-mysql, hoffe das hilft

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top