Teniendo en cuenta que realizaré cálculos en pares lat / long, ¿qué tipo de datos es el más adecuado para usar con una base de datos MySQL?
Teniendo en cuenta que realizaré cálculos en pares lat / long, ¿qué tipo de datos es el más adecuado para usar con una base de datos MySQL?
Respuestas:
Use las extensiones espaciales de MySQL con SIG.
Google proporciona una solución PHP / MySQL de principio a fin para una aplicación de ejemplo "Localizador de tiendas" con Google Maps. En este ejemplo, almacenan los valores lat / lng como "Float" con una longitud de "10,6"
FLOAT(10,6)
deja 4 dígitos para la parte entera de la coordenada. Y no, el signo no cuenta, eso proviene del atributo (no) firmado.
Double
de datos para Laravel
Básicamente depende de la precisión que necesita para sus ubicaciones. Usando DOUBLE tendrás una precisión de 3.5nm. DECIMAL (8,6) / (9,6) baja a 16 cm. FLOTADOR es 1.7m ...
Esta tabla muy interesante tiene una lista más completa: 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
Espero que esto ayude.
Las extensiones espaciales de MySQL son la mejor opción porque tiene la lista completa de operadores e índices espaciales a su disposición. Un índice espacial le permitirá realizar cálculos basados en la distancia muy rápidamente. Tenga en cuenta que a partir de 6.0, la extensión espacial aún está incompleta. No estoy dejando de lado MySQL Spatial, solo para informarles sobre las trampas antes de avanzar demasiado en esto.
Si está tratando estrictamente con puntos y solo con la función DISTANCE, está bien. Si necesita hacer algún cálculo con polígonos, líneas o puntos almacenados, los operadores espaciales no proporcionan resultados exactos a menos que use el operador "relacionar". Vea la advertencia en la parte superior de 21.5.6 . Las relaciones como contiene, dentro o intersectan están utilizando el MBR, no la forma geométrica exacta (es decir, una Elipse se trata como un Rectángulo).
Además, las distancias en MySQL Spatial están en las mismas unidades que su primera geometría. Esto significa que si está usando grados decimales, sus mediciones de distancia están en grados decimales. Esto hará que sea muy difícil obtener resultados exactos a medida que salga del ecuador.
Cuando hice esto para una base de datos de navegación construida a partir de ARINC424, hice una buena cantidad de pruebas y, mirando hacia atrás en el código, utilicé un DECIMAL (18,12) (en realidad un NUMERIC (18,12) porque era firebird).
Los flotadores y los dobles no son tan precisos y pueden dar lugar a errores de redondeo que pueden ser algo muy malo. No recuerdo si encontré datos reales que tenían problemas, pero estoy bastante seguro de que la imposibilidad de almacenar con precisión en un flotante o un doble podría causar problemas
El punto es que cuando usamos grados o radianes sabemos el rango de los valores, y la parte fraccionaria necesita la mayor cantidad de dígitos.
Las extensiones espaciales de MySQL son una buena alternativa porque siguen el modelo de geometría OpenGIS . No los usé porque necesitaba mantener mi base de datos portátil.
a*b
no era igual b*a
(para algunos valores). Había muchos ejemplos algo así como: 2+2 = 3.9999
. El estándar limpió mucho desorden, y fue adoptado 'rápidamente' por prácticamente todas las piezas de hardware y software. Entonces, esta discusión ha sido válida, no solo desde 2008, sino durante un tercio de siglo.
Depende de la precisión que requiera.
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
De: http://mysql.rjweb.org/doc.php/latlng
Resumir:
DOUBLE
.DECIMAL(8,6)/(9,6)
.A partir de MySQL 5.7 , considere usar Tipos de datos espaciales (SDT), específicamente POINT
para almacenar una sola coordenada. Antes de 5.7, SDT no admite índices (con la excepción de 5.6 cuando el tipo de tabla es MyISAM).
Nota:
POINT
clase, el orden de los argumentos para almacenar coordenadas debe ser POINT(latitude, longitude)
.ST_Distance
) y determinar si un punto está contenido dentro de otra área ( ST_Contains
).CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM;
y la advertencia sobre las limitaciones de SDT, como James mencionó , tal vez su respuesta sea más concisa y precisa para ayudar a otras personas también. ..
Basado en este artículo wiki http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy, el tipo de datos apropiado en MySQL es Decimal (9,6) para almacenar la longitud y la latitud en campos separados.
Úselo DECIMAL(8,6)
para la latitud (90 a -90 grados) y DECIMAL(9,6)
para la longitud (180 a -180 grados). 6 decimales están bien para la mayoría de las aplicaciones. Ambos deben estar "firmados" para permitir valores negativos.
DECIMAL
tipo está destinado a cálculos financieros donde no floor/ceil
se acepta ningún . El llano FLOAT
supera significativamente DECIMAL
.
No es necesario ir lejos, según Google Maps, lo mejor es FLOTAR (10,6) para lat y lng.
lat FLOAT( 10, 6 ) NOT NULL,
lng FLOAT( 10, 6 ) NOT NULL
FLOAT
sintaxis está obsoleta a partir de mysql 8.0.17
. Mysql ahora recomienda usar FLOAT
sin parámetros de precisión dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html y dev.mysql.com/doc/refman/5.5/en/floating-point- types.html
Almacenamos latitud / longitud X 1,000,000 en nuestra base de datos Oracle como NÚMEROS para evitar errores de redondeo con dobles.
Dado que la latitud / longitud hasta el sexto lugar decimal era 10 cm de precisión, eso era todo lo que necesitábamos. Muchas otras bases de datos también almacenan lat / long al sexto lugar decimal.
En una perspectiva completamente diferente y más simple:
VARCHAR
), por ejemplo: " -0000.0000001, -0000.000000000000001 " (longitud 35 y si un número tiene más de 7 dígitos decimales, entonces se redondea);google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
De esta manera, no necesita preocuparse por indexar números y todos los demás problemas asociados con los tipos de datos que pueden arruinar sus coordenadas.
dependiendo de su aplicación, sugiero usar FLOAT (9,6)
las teclas espaciales le darán más funciones, pero en los puntos de referencia de producción los flotadores son mucho más rápidos que las teclas espaciales. (0,01 VS 0,001 en AVG)
MySQL usa double para todos los flotantes ... Así que usa type double. El uso de flotante dará lugar a valores redondeados impredecibles en la mayoría de las situaciones.
DOUBLE
. MySQL le permite almacenar datos como 4 bytes FLOAT
u 8 bytes DOUBLE
. Por lo tanto, es probable que haya una pérdida de precisión al almacenar una expresión en una FLOAT
columna.
Si bien no es óptimo para todas las operaciones, si está haciendo mosaicos de mapas o trabajando con grandes cantidades de marcadores (puntos) con una sola proyección (por ejemplo, Mercator, como Google Maps y muchos otros marcos de mapas resbaladizos esperan), he encontrado lo que Yo llamo "Vast Coordinate System" para ser muy, muy útil. Básicamente, almacena las coordenadas de píxel x e y de alguna manera ampliada: utilizo el nivel de zoom 23. Esto tiene varios beneficios:
Hablé sobre todo esto en una reciente publicación de blog: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/
Estoy muy sorprendido por algunas respuestas / comentarios.
¿Por qué alguien estaría dispuesto a "disminuir" la precisión, y luego realizar cálculos con los peores números? Suena en última instancia estúpido.
Si la fuente tiene una precisión de 64 bits, ciertamente sería tonto arreglar la escala de forma voluntaria, por ejemplo. 6 decimales, y limite la precisión a un máximo de 9 dígitos significativos (lo que sucede con el formato decimal 9.6 comúnmente propuesto).
Naturalmente, uno almacena los datos con la precisión que tiene el material de origen. La única razón para disminuir la precisión sería un espacio de almacenamiento limitado.
El formato decimal 9.6 provoca un fenómeno de ajuste a la cuadrícula. Ese debería ser el último paso, si es que va a suceder.
No invitaría errores acumulados a mi nido.
TL; DR
Use FLOAT (8,5) si no está trabajando en la NASA / militares y no está haciendo sistemas de aeronaves navi.
Para responder completamente a su pregunta, deberá considerar varias cosas:
Formato
Entonces, la primera parte de la respuesta sería: puede almacenar las coordenadas en el formato que utiliza su aplicación para evitar conversiones constantes de un lado a otro y hacer consultas SQL más simples.
Lo más probable es que use Google Maps u OSM para mostrar sus datos, y GMaps está usando el formato "grados decimales 2". Por lo tanto, será más fácil almacenar coordenadas en el mismo formato.
Precisión
Luego, le gustaría definir la precisión que necesita. Por supuesto, puede almacenar coordenadas como "-32.608697550570334,21.278081997935146", pero ¿alguna vez le han importado los milímetros mientras navegaba al punto? Si no está trabajando en la NASA y no está haciendo satélites o cohetes o trayectorias de aviones, debería estar bien con una precisión de varios metros.
El formato de uso común es de 5 dígitos después de los puntos, lo que le brinda una precisión de 50 cm.
Ejemplo : hay una distancia de 1 cm entre X, 21.278081 8 y X, 21.278081 9 . Entonces, 7 dígitos después del punto le dan precisión de 1 / 2cm y 5 dígitos después del punto le darán precisión de 1/2 metros (porque la distancia mínima entre puntos distintos es 1m, por lo que el error de redondeo no puede ser más de la mitad). Para la mayoría de los propósitos civiles, debería ser suficiente.
grados formato de minutos decimales (40 ° 26.767 ′ N 79 ° 58.933 ′ W) le ofrece exactamente la misma precisión que 5 dígitos después del punto
Almacenamiento de espacio eficiente
Si seleccionó el formato decimal, su coordenada es un par (-32.60875, 21.27812). Obviamente, 2 x (1 bit para signo, 2 dígitos para grados y 5 dígitos para exponente) serán suficientes.
Así que aquí me gustaría apoyar a Alix Axel de los comentarios que dicen que la sugerencia de Google para almacenarlo en FLOAT (10,6) es realmente adicional, porque no necesita 4 dígitos para la parte principal (ya que el signo está separado y la latitud es limitada a 90 y la longitud se limita a 180). Puede usar fácilmente FLOAT (8,5) para una precisión de 1 / 2m o FLOAT (9,6) para una precisión de 50 / 2cm. O incluso puede almacenar lat y long en tipos separados, porque FLOAT (7,5) es suficiente para lat. Consulte la referencia de tipos flotantes de MySQL . Cualquiera de ellos será como FLOAT normal e igual a 4 bytes de todos modos.
Por lo general, el espacio no es un problema hoy en día, pero si desea optimizar realmente el almacenamiento por alguna razón (Descargo de responsabilidad: no optimice previamente), puede comprimir lat (no más de 91 000 valores + signo) + largo (no más de 181 000 valores + signo) a 21 bits, que es significativamente menor que 2xFLOAT (8 bytes == 64 bits)
Las funciones espaciales en PostGIS son mucho más funcionales (es decir, no están limitadas a las operaciones de BBOX) que las de las funciones espaciales de MySQL. Compruébalo: texto del enlace
Las latitudes varían de -90 a +90 (grados), por lo que DECIMAL (10, 8) está bien para eso
las longitudes varían de -180 a +180 (grados), por lo que necesita DECIMAL (11, 8).
Nota: El primer número es el número total de dígitos almacenados, y el segundo es el número después del punto decimal.
En breve: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL
Le sugiero que use el tipo de datos Float para SQL Server.
Los cálculos Lat Long requieren precisión, por lo tanto, utilice algún tipo de tipo decimal y haga que la precisión sea al menos 2 mayor que el número que almacenará para realizar los cálculos matemáticos. No conozco los tipos de datos de mi sql, pero en el servidor SQL la gente a menudo usa flotante o real en lugar de decimal y se mete en problemas porque estos son números estimados, no números reales. Así que solo asegúrese de que el tipo de datos que usa sea un tipo decimal verdadero y no un tipo decimal flotante y que debería estar bien.
A FLOAT
debería darle toda la precisión que necesita y ser mejor para las funciones de comparación que almacenar cada coordenada como una cadena o similar.
Sin embargo, si su versión de MySQL es anterior a la 5.0.3, es posible que tenga que prestar atención a ciertos errores de comparación de coma flotante .
Antes de MySQL 5.0.3, las columnas DECIMAL almacenan valores con precisión exacta porque se representan como cadenas, pero los cálculos de los valores DECIMAL se realizan mediante operaciones de punto flotante. A partir de 5.0.3, MySQL realiza operaciones DECIMAL con una precisión de 64 dígitos decimales, lo que debería resolver los problemas de imprecisión más comunes cuando se trata de columnas DECIMAL
DECIMAL
tenía (antes de 5.0.3) ciertos errores debido al uso de la implementación flotante.