it-swarm.com.de

Datenbank: Optimale Methode zum Abfragen von Geostandortdaten?

Ich habe eine MySQL-Datenbank. Ich speichere Häuser in der Datenbank und führe buchstäblich nur 1 Abfrage für die Datenbank aus, aber ich muss diese Abfrage superschnell ausführen , und das ist, um alle Häuser innerhalb eines quadratischen Feldes mit geografischem Breitengrad & zurückzugeben. Längengrad.

SELECT * FROM homes 
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???

Wie speichere ich meine Geodaten am besten, damit ich diese Abfrage zum Anzeigen der gesamten Heimat im Geolocation-Feld am schnellsten durchführen kann?

Grundsätzlich gilt:

  • Verwende ich die beste SQL-Anweisung, um diese Abfrage am schnellsten auszuführen?
  • Gibt es eine andere Methode, die es mir ermöglicht, das Ergebnis von Häusern innerhalb einer geolokalisierten Box auf schnellstem Wege abzufragen, möglicherweise ohne eine Datenbank zu verwenden?

Falls es hilft, habe ich mein Datenbanktabellenschema unten angegeben:

CREATE TABLE IF NOT EXISTS `homes` (
  `home_id` int(10) unsigned NOT NULL auto_increment,
  `address` varchar(128) collate utf8_unicode_ci NOT NULL,
  `city` varchar(64) collate utf8_unicode_ci NOT NULL,
  `state` varchar(2) collate utf8_unicode_ci NOT NULL,
  `Zip` mediumint(8) unsigned NOT NULL,
  `price` mediumint(8) unsigned NOT NULL,
  `sqft` smallint(5) unsigned NOT NULL,
  `year_built` smallint(5) unsigned NOT NULL,
  `geolat` decimal(10,6) default NULL,
  `geolng` decimal(10,6) default NULL,
  PRIMARY KEY  (`home_id`),
  KEY `geolat` (`geolat`),
  KEY `geolng` (`geolng`),
) ENGINE=InnoDB  ;

UPDATE

Ich verstehe, dass der räumliche Wille die Erdkrümmung berücksichtigt, aber ich bin am schnellsten daran interessiert, Geodaten zurückzugeben. Sofern diese Pakete für räumliche Datenbanken keine Daten schneller zurückgeben, empfehlen Sie keine räumlichen Erweiterungen. Vielen Dank

UPDATE 2

Bitte beachten Sie, dass unten niemand die Frage wirklich beantwortet hat. Ich freue mich sehr auf jede Unterstützung, die ich erhalten könnte. Danke im Voraus.

36
HankW

Es gibt ein gutes Dokument zur MySQL-Geolocation-Leistung hier .

EDIT Ziemlich sicher, dass hier ein fester Radius verwendet wird. Ich bin auch nicht zu 100% sicher, dass der Algorithmus zum Berechnen der Entfernung am weitesten fortgeschritten ist (d. H. Er bohrt durch die Erde).

Bezeichnend ist, dass der Algorithmus billig ist, um Ihnen ein Limit für die Anzahl der Reihen für die richtige Abstandssuche zu geben.


Der Algorithmus filtert vor, indem er die Kandidaten in einem Quadrat um den Quellpunkt nimmt und dann die Entfernung in miles berechnet.

Berechnen Sie dies vorab oder verwenden Sie eine gespeicherte Prozedur als Quelle:

# Pseudo code
# user_lon and user_lat are the source longitude and latitude
# radius is the radius where you want to search
lon_distance = radius / abs(cos(radians(user_lat))*69);
min_lon = user_lon - lon_distance;
max_lon = user_lon + lon_distance;
min_lat = user_lat - (radius / 69);
max_lat = user_lat + (radius / 69);
SELECT dest.*,
  3956 * 2 * ASIN(
    SQRT(
      POWER(
        SIN(
          (user_lat - dest.lat) * pi() / 180 / 2
        ), 2
      ) + COS(
        user_lat * pi() / 180
      ) * COS(
        dest.lat * pi() / 180
      ) * POWER(
        SIN(
          (user_lon - dest.lon) * pi() / 180 / 2
        ), 2
      )
    )
  ) as distance
FROM dest
WHERE 
  dest.lon between min_lon and max_lon AND
  dest.lat between min_lat and max_lat
HAVING distance < radius
ORDER BY distance
LIMIT 10
13
Igor Zevaka

Ich hatte das gleiche Problem und schrieb einen dreiteiligen Blogpost. Dies war schneller als der Geo-Index.

Intro , Benchmark , SQL

4
Evert

Wenn Sie sich wirklich für die Leistung entscheiden müssen, können Sie Begrenzungsrahmen für Ihre Daten definieren und die Begrenzungsrahmen vor der Berechnung den Objekten beim Einfügen zuordnen und später für Abfragen verwenden.

Wenn die Ergebnismengen relativ klein sind, können Sie dennoch Genauigkeitskorrekturen in der Anwendungslogik vornehmen (horizontal horizontal skalierbar als eine Datenbank) und dabei genaue Ergebnisse liefern.

Werfen Sie einen Blick auf Bret Slatkins geobox.py , das eine großartige Dokumentation für den Ansatz enthält.

Ich würde dennoch empfehlen, PostgreSQL und PostGIS im Vergleich zu MySQL zu überprüfen, wenn Sie in absehbarer Zeit komplexere Abfragen durchführen möchten.

2
tosh

Hier ist ein Trick, den ich mit etwas Erfolg verwendet habe, um Rundungsbereiche zu erstellen. Das heißt, wenn Sie einen Ort mit dem Wert 36.12345, -120.54321 haben und ihn mit anderen Orten gruppieren möchten, die sich in einem ungefähren Raster befinden, können Sie den Bereich 36.12x-120.54 und Alle anderen Standorte mit derselben Abrundungsregion werden in ein und dasselbe Feld gestellt.

Offensichtlich erhalten Sie dadurch keinen sauberen Radius, d. H. Wenn der von Ihnen betrachtete Ort näher an einem Rand liegt als an einem anderen. Mit dieser Art von Setup ist es jedoch leicht genug, die acht Kästchen zu berechnen, die das Kästchen Ihres Hauptstandorts umgeben. Nämlich:

[36.13x-120.55][36.13x-120.54][36.13x-120.53]
[36.12x-120.55][36.12x-120.54][36.12x-120.53]
[36.11x-120.55][36.11x-120.54][36.11x-120.53]

Ziehen Sie alle Standorte mit übereinstimmenden Abrundungsetiketten heraus. Sobald Sie sie aus der Datenbank entfernt haben, können Sie mithilfe der Entfernungsberechnungen ermitteln, welche Standorte verwendet werden sollen.

1
Ben

Die von Ihnen verwendeten Indizes sind in der Tat B-Tree-Indizes und unterstützen das Schlüsselwort BETWEEN in Ihrer Abfrage. Dies bedeutet, dass der Optimierer Ihre Indizes verwenden kann, um die Häuser in Ihrer "Box" zu finden. Dies bedeutet jedoch nicht, dass die Indizes immer verwendet werden. Wenn Sie einen Bereich angeben, der zu viele "Treffer" enthält, werden die Indizes nicht verwendet.

1
Peter Lindqvist

Seit MySQL 5.7 kann mysql geoindex wie ST_Distance_Sphere () und ST_Contains () verwenden, was die Leistung verbessert.

0
Anak1

Eine sehr gute Alternative ist MongoDB mit seiner Geospatial Indexing .

0
jalogar

Häuser? Sie werden wahrscheinlich nicht einmal zehntausend davon haben. Verwenden Sie einfach einen In-Memory-Index wie STRTree .

0
novalis

Das sieht ziemlich schnell aus. Meine einzige Sorge wäre, dass ein Index verwendet wird, um alle Werte innerhalb von 3 Meilen vom Breitengrad abzurufen und diese dann nach Werten innerhalb von 3 Meilen vom Längengrad zu filtern. Wenn ich verstehe, wie das zugrunde liegende System funktioniert, können Sie nur einen INDEX pro Tabelle verwenden, sodass entweder der Index für lat oder long wertlos ist.

Wenn Sie über eine große Datenmenge verfügten, beschleunigte möglicherweise die Eingabe einer eindeutigen logischen ID für jedes Quadrat mit einer Länge von 1 x 1 Meile. Anschließend wurde die SELECT-Funktion (area = "23234/34234") zusätzlich eingeschränkt. OR area = "23235/34234" OR ...) für alle Quadrate um Ihren Punkt. Erzwingen Sie dann, dass die Datenbank diesen Index anstelle des lat und long verwendet. Dann filtern Sie nur noch viel weniger Quadratmeilen an Daten.

Bei Ihrem derzeitigen Ansatz sollten Sie eine Änderung vornehmen, Anstatt Geolat und Geolong separat zu indizieren, sollten Sie einen zusammengesetzten Index haben: 

KEY `geolat_geolng` (`geolat`, `geolng`),

Derzeit nutzt Ihre Anfrage nur einen der beiden Indizes.

0
Ben

Sie können eine separate Tabelle 'GeoLocations' erstellen, die einen Primärschlüssel von ('geolat', 'geolng') und eine Spalte mit der home_id enthält, falls diese bestimmte geolocation ein Zuhause hat. Dies sollte es dem Optimierer ermöglichen, nach einer Reihe von geografischen Standorten zu suchen, die auf der Festplatte nach einer Liste von home_ids sortiert werden. Sie können dann eine Verknüpfung mit Ihrer 'home'-Tabelle durchführen, um Informationen zu diesen home_ids zu finden.

CREATE TABLE IF NOT EXISTS `GeoLocations` (
`geolat` decimal(10,6) NOT NULL,
`geolng` decimal(10,6) NOT NULL,
`home_id` int(10) NULL
PRIMARY KEY  (`geolat`,`geolng`)
);

SELECT GL.home_id
FROM GeoLocations GL
INNER JOIN Homes H
 ON GL.home_id = H.home_id
WHERE GL.geolat between X and Y
 and GL.geolng between X and Y
0
Clayton Stewart