In Anbetracht dessen, dass ich Berechnungen für Lat / Long-Paare durchführen werde, welcher Datentyp eignet sich am besten für die Verwendung mit einer MySQL-Datenbank?
In Anbetracht dessen, dass ich Berechnungen für Lat / Long-Paare durchführen werde, welcher Datentyp eignet sich am besten für die Verwendung mit einer MySQL-Datenbank?
Antworten:
Verwenden Sie die räumlichen Erweiterungen von MySQL mit GIS.
Google bietet eine Start-zu-Ende-PHP / MySQL-Lösung für eine Beispielanwendung "Store Locator" mit Google Maps. In diesem Beispiel speichern sie die lat / lng-Werte als "Float" mit einer Länge von "10,6".
FLOAT(10,6)
4 Ziffern für den ganzzahligen Teil der Koordinate. Und nein, das Zeichen zählt nicht - das kommt vom (nicht) signierten Attribut.
Double
für Laravel
Grundsätzlich hängt es von der Präzision ab, die Sie für Ihre Standorte benötigen. Mit DOUBLE haben Sie eine Genauigkeit von 3,5 nm. DECIMAL (8,6) / (9,6) geht auf 16 cm zurück. FLOAT ist 1,7m ...
Diese sehr interessante Tabelle enthält eine vollständigere Liste: http://mysql.rjweb.org/doc.php/latlng :
Datatype Bytes Resolution
Deg*100 (SMALLINT) 4 1570 m 1.0 mi Cities
DECIMAL(4,2)/(5,2) 5 1570 m 1.0 mi Cities
SMALLINT scaled 4 682 m 0.4 mi Cities
Deg*10000 (MEDIUMINT) 6 16 m 52 ft Houses/Businesses
DECIMAL(6,4)/(7,4) 7 16 m 52 ft Houses/Businesses
MEDIUMINT scaled 6 2.7 m 8.8 ft
FLOAT 8 1.7 m 5.6 ft
DECIMAL(8,6)/(9,6) 9 16cm 1/2 ft Friends in a mall
Deg*10000000 (INT) 8 16mm 5/8 in Marbles
DOUBLE 16 3.5nm ... Fleas on a dog
Hoffe das hilft.
Die räumlichen Erweiterungen von MySQL sind die beste Option, da Ihnen die vollständige Liste der räumlichen Operatoren und Indizes zur Verfügung steht. Mit einem räumlichen Index können Sie sehr schnell entfernungsbasierte Berechnungen durchführen. Bitte beachten Sie, dass ab 6.0 die Spatial Extension noch unvollständig ist. Ich lege MySQL Spatial nicht ab, sondern informiere Sie nur über die Fallstricke, bevor Sie zu weit kommen.
Wenn Sie sich ausschließlich mit Punkten und nur mit der Funktion DISTANCE befassen, ist dies in Ordnung. Wenn Sie Berechnungen mit Polygonen, Linien oder gepufferten Punkten durchführen müssen, liefern die räumlichen Operatoren keine genauen Ergebnisse, es sei denn, Sie verwenden den Operator "beziehen". Siehe die Warnung oben in 21.5.6 . Beziehungen wie enthalten, innerhalb oder Schnittpunkte verwenden den MBR, nicht die exakte Geometrieform (dh eine Ellipse wird wie ein Rechteck behandelt).
Außerdem sind die Abstände in MySQL Spatial in den gleichen Einheiten wie bei Ihrer ersten Geometrie. Dies bedeutet, wenn Sie Dezimalgrade verwenden, werden Ihre Entfernungsmessungen in Dezimalgraden angegeben. Dies macht es sehr schwierig, genaue Ergebnisse zu erhalten, wenn Sie weiter vom Äquator entfernt sind.
Als ich dies für eine Navigationsdatenbank aus ARINC424 tat, habe ich eine ganze Reihe von Tests durchgeführt und im Rückblick auf den Code ein DECIMAL (18,12) (eigentlich ein NUMERIC (18,12) verwendet, weil es ein Feuervogel war).
Floats und Doubles sind nicht so präzise und können zu Rundungsfehlern führen, die sehr schlecht sein können. Ich kann mich nicht erinnern, ob ich echte Daten gefunden habe, bei denen Probleme aufgetreten sind - aber ich bin mir ziemlich sicher, dass die Unfähigkeit, genau in einem Float oder Double zu speichern, Probleme verursachen kann
Der Punkt ist, dass wir bei der Verwendung von Grad oder Bogenmaß den Bereich der Werte kennen - und der Bruchteil die meisten Ziffern benötigt.
Die MySQL Spatial Extensions sind eine gute Alternative, da sie dem OpenGIS-Geometriemodell folgen . Ich habe sie nicht verwendet, weil ich meine Datenbank portabel halten musste.
a*b
nicht gleich war b*a
(für einige Werte). Es gab viele Beispiele wie : 2+2 = 3.9999
. Der Standard räumte viel Chaos auf und wurde von praktisch jeder Hardware und Software „schnell“ übernommen. Diese Diskussion ist also nicht nur seit 2008 gültig, sondern seit einem Drittel eines Jahrhunderts.
Hängt von der Präzision ab, die Sie benötigen.
Datatype Bytes resolution
------------------ ----- --------------------------------
Deg*100 (SMALLINT) 4 1570 m 1.0 mi Cities
DECIMAL(4,2)/(5,2) 5 1570 m 1.0 mi Cities
SMALLINT scaled 4 682 m 0.4 mi Cities
Deg*10000 (MEDIUMINT) 6 16 m 52 ft Houses/Businesses
DECIMAL(6,4)/(7,4) 7 16 m 52 ft Houses/Businesses
MEDIUMINT scaled 6 2.7 m 8.8 ft
FLOAT 8 1.7 m 5.6 ft
DECIMAL(8,6)/(9,6) 9 16cm 1/2 ft Friends in a mall
Deg*10000000 (INT) 8 16mm 5/8 in Marbles
DOUBLE 16 3.5nm ... Fleas on a dog
Von: http://mysql.rjweb.org/doc.php/latlng
Zusammenfassen:
DOUBLE
.DECIMAL(8,6)/(9,6)
.Ab MySQL 5.7 sollten Sie die Verwendung von Spatial Data Types (SDT) in Betracht ziehen , insbesondere POINT
zum Speichern einer einzelnen Koordinate. Vor 5.7 unterstützt SDT keine Indizes (mit Ausnahme von 5.6, wenn der Tabellentyp MyISAM ist).
Hinweis:
POINT
class muss die Reihenfolge der Argumente zum Speichern von Koordinaten lauten POINT(latitude, longitude)
.ST_Distance
) und die Bestimmung, ob ein Punkt in einem anderen Bereich enthalten ist ( ST_Contains
).CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
und die Warnung vor SDT-Einschränkungen hinzufügen , wie James erwähnte , wird Ihre Antwort möglicherweise präziser und präziser sein, um auch anderen Menschen zu helfen. ..
Basierend auf diesem Wiki-Artikel http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy ist der geeignete Datentyp in MySQL Decimal (9,6) zum Speichern von Längen- und Breitengrad in separaten Feldern.
Verwenden Sie DECIMAL(8,6)
für Breitengrad (90 bis -90 Grad) und DECIMAL(9,6)
für Längengrad (180 bis -180 Grad). 6 Dezimalstellen sind für die meisten Anwendungen ausreichend. Beide sollten "signiert" sein, um negative Werte zu berücksichtigen.
DECIMAL
Typ ist für Finanzberechnungen vorgesehen, bei denen keine floor/ceil
akzeptiert wird. Plain FLOAT
übertrifft deutlich DECIMAL
.
Laut Google Maps müssen Sie nicht weit gehen. Das Beste ist FLOAT (10,6) für lat und lng.
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
als ob die Syntax ab veraltet ist mysql 8.0.17
. MySQL empfiehlt jetzt, nur FLOAT
ohne Präzisionsparameter dev.mysql.com/doc/refman/8.0/de/numeric-type-overview.html und dev.mysql.com/doc/refman/5.5/en/floating-point- zu verwenden. types.html
Wir speichern Breiten- / Längengrade X 1.000.000 in unserer Orakel-Datenbank als ZAHLEN, um Rundungsfehler mit Doppelwerten zu vermeiden.
Angesichts der Tatsache, dass der Breiten- / Längengrad bis zur 6. Dezimalstelle 10 cm genau war, war dies alles, was wir brauchten. Viele andere Datenbanken speichern Lat / Long ebenfalls bis zur 6. Dezimalstelle.
In einer ganz anderen und einfacheren Perspektive:
VARCHAR
), z. B.: " -0000.0000001, -0000.0000000000001 " (35 Länge und wenn eine Zahl mehr als 7 Dezimalstellen hat, wird sie gerundet);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
Auf diese Weise müssen Sie sich keine Gedanken über die Indizierung von Zahlen und all die anderen Probleme machen, die mit Datentypen verbunden sind, die Ihre Koordinaten verfälschen können.
Abhängig von Ihrer Anwendung empfehle ich die Verwendung von FLOAT (9,6).
Mit räumlichen Schlüsseln erhalten Sie mehr Funktionen, aber bei Produktionsbenchmarks sind die Floats viel schneller als die räumlichen Schlüssel. (0,01 VS 0,001 in AVG)
MySQL verwendet double für alle Floats ... Verwenden Sie also type double. Die Verwendung von float führt in den meisten Situationen zu unvorhersehbaren gerundeten Werten
DOUBLE
. MySQL können Sie speichern Daten entweder als ein 4-Byte FLOAT
oder ein 8-Byte DOUBLE
. Es ist also wahrscheinlich, dass beim Speichern eines Ausdrucks in einer FLOAT
Spalte ein Genauigkeitsverlust auftritt .
Es ist zwar nicht für alle Vorgänge optimal, aber wenn Sie Kartenkacheln erstellen oder mit einer großen Anzahl von Markierungen (Punkten) mit nur einer Projektion arbeiten (z. B. Mercator, wie Google Maps und viele andere rutschige Karten-Frameworks erwarten), habe ich was gefunden Ich nenne "Vast Coordinate System", um wirklich sehr, sehr praktisch zu sein. Grundsätzlich speichern Sie die x- und y-Pixelkoordinaten in einer vergrößerten Richtung - ich verwende die Zoomstufe 23. Dies hat mehrere Vorteile:
Ich habe kürzlich in einem Blogbeitrag darüber gesprochen: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
Ich bin sehr überrascht von einigen Antworten / Kommentaren.
Warum um alles in der Welt sollte jemand bereit sein, die Genauigkeit freiwillig "vorab zu verringern" und später Berechnungen für die schlechteren Zahlen durchzuführen? Klingt letztendlich dumm.
Wenn die Quelle eine 64-Bit-Genauigkeit hat, wäre es sicherlich dumm, die Skalierung freiwillig auf z. 6 Dezimalstellen und beschränken Sie die Genauigkeit auf maximal 9 signifikante Stellen (was beim allgemein vorgeschlagenen Dezimalformat 9.6 der Fall ist).
Natürlich speichert man die Daten mit der Genauigkeit, die das Quellmaterial hat. Der einzige Grund, die Genauigkeit zu verringern, wäre begrenzter Speicherplatz.
Das dezimale 9.6-Format verursacht ein Snap-to-Grid-Phänomen. Das sollte der allerletzte Schritt sein, wenn es überhaupt passieren soll.
Ich würde keine akkumulierten Fehler in mein Nest einladen.
TL; DR
Verwenden Sie FLOAT (8,5), wenn Sie nicht in der NASA / im Militär arbeiten und keine Flugzeugnavigationssysteme herstellen.
Um Ihre Frage vollständig zu beantworten, müssen Sie verschiedene Dinge berücksichtigen:
Format
Der erste Teil der Antwort wäre also: Sie können die Koordinaten in dem Format speichern, das Ihre Anwendung verwendet , um ständige Konvertierungen hin und her zu vermeiden und einfachere SQL-Abfragen durchzuführen.
Höchstwahrscheinlich verwenden Sie Google Maps oder OSM, um Ihre Daten anzuzeigen, und GMaps verwendet das Format "Dezimalgrad 2". So ist es einfacher, Koordinaten im selben Format zu speichern.
Präzision
Dann möchten Sie die Präzision definieren, die Sie benötigen. Natürlich können Sie Koordinaten wie "-32.608697550570334,21.278081997935146" speichern, aber haben Sie sich jemals um Millimeter gekümmert, während Sie zum Punkt navigieren? Wenn Sie nicht in der NASA arbeiten und keine Satelliten-, Raketen- oder Flugzeugflugbahnen ausführen, sollten Sie mit einer Genauigkeit von mehreren Metern in Ordnung sein.
Das häufig verwendete Format ist 5 Stellen nach Punkten, was eine Genauigkeit von 50 cm ergibt.
Beispiel : Zwischen X, 21.278081 8 und X, 21.278081 9 besteht ein Abstand von 1 cm . 7 Stellen nach dem Punkt ergeben also eine Genauigkeit von 1/2 cm und 5 Stellen nach dem Punkt ergeben eine Genauigkeit von 1/2 m (da der minimale Abstand zwischen verschiedenen Punkten 1 m beträgt und der Rundungsfehler nicht mehr als die Hälfte davon betragen kann). Für die meisten zivilen Zwecke sollte es ausreichen.
Das Grad-Dezimal-Minuten-Format (40 ° 26.767 ′ N 79 ° 58.933 ′ W) bietet genau die gleiche Genauigkeit wie 5 Stellen nach dem Punkt
Platzsparende Lagerung
Wenn Sie das Dezimalformat ausgewählt haben, ist Ihre Koordinate ein Paar (-32.60875, 21.27812). Offensichtlich reichen 2 x (1 Bit für Vorzeichen, 2 Stellen für Grad und 5 Stellen für Exponenten) aus.
Hier möchte ich Alix Axel aus Kommentaren unterstützen, die besagen, dass der Vorschlag von Google, es in FLOAT (10,6) zu speichern, wirklich extra ist, da Sie keine 4 Ziffern für den Hauptteil benötigen (da das Vorzeichen getrennt und der Breitengrad begrenzt ist bis 90 und der Längengrad ist auf 180 begrenzt). Sie können FLOAT (8,5) problemlos für eine Genauigkeit von 1 / 2m oder FLOAT (9,6) für eine Genauigkeit von 50 / 2cm verwenden. Oder Sie können lat und long sogar in getrennten Typen speichern, da FLOAT (7,5) für lat ausreicht. Siehe Referenz zu MySQL-Float-Typen . Jeder von ihnen ist wie normaler FLOAT und entspricht sowieso 4 Bytes.
Normalerweise ist Speicherplatz heutzutage kein Problem, aber wenn Sie den Speicher aus irgendeinem Grund wirklich optimieren möchten (Haftungsausschluss: Führen Sie keine Voroptimierung durch), können Sie lat (nicht mehr als 91 000 Werte + Vorzeichen) + long (Nr mehr als 181 000 Werte + Vorzeichen) auf 21 Bit, was deutlich weniger als 2xFLOAT (8 Bytes == 64 Bit) ist
Die Breiten reichen von -90 bis +90 (Grad), daher ist DECIMAL (10, 8) dafür in Ordnung
Die Längen reichen von -180 bis +180 (Grad), daher benötigen Sie DECIMAL (11, 8).
Hinweis: Die erste Zahl ist die Gesamtzahl der gespeicherten Ziffern und die zweite die Zahl nach dem Dezimalpunkt.
Zusamenfassend: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Ich schlage vor, Sie verwenden den Float-Datentyp für SQL Server.
Lat Long-Berechnungen erfordern Genauigkeit. Verwenden Sie daher eine Art Dezimaltyp und stellen Sie die Genauigkeit mindestens 2 höher als die Zahl ein, die Sie speichern, um mathematische Berechnungen durchzuführen. Ich weiß nichts über meine SQL-Datentypen, aber in SQL Server verwenden die Leute häufig float oder real anstelle von dezimal und geraten in Schwierigkeiten, da es sich um geschätzte Zahlen handelt, die nicht real sind. Stellen Sie also sicher, dass der von Ihnen verwendete Datentyp ein echter Dezimaltyp und kein schwebender Dezimaltyp ist, und es sollte Ihnen gut gehen.
A FLOAT
sollte Ihnen die erforderliche Präzision bieten und für Vergleichsfunktionen besser geeignet sein, als jede Koordinate als Zeichenfolge oder dergleichen zu speichern.
Wenn Ihre MySQL-Version älter als 5.0.3 ist, müssen Sie möglicherweise bestimmte Gleitkomma-Vergleichsfehler berücksichtigen .
Vor MySQL 5.0.3 speichern DECIMAL-Spalten Werte mit exakter Genauigkeit, da sie als Zeichenfolgen dargestellt werden. Berechnungen für DECIMAL-Werte werden jedoch mithilfe von Gleitkommaoperationen durchgeführt. Ab 5.0.3 führt MySQL DECIMAL-Operationen mit einer Genauigkeit von 64 Dezimalstellen aus, wodurch die häufigsten Ungenauigkeitsprobleme bei DECIMAL-Spalten gelöst werden sollten
DECIMAL
(vor 5.0.3) bestimmte Fehler aufgrund der Verwendung der schwebenden Implementierung aufgetreten sind.