Какой идеальный тип данных использовать для хранения широты / долготы в базе данных MySQL?

387

Принимая во внимание, что я буду выполнять вычисления на партах lat/long, какой тип данных лучше всего подходит для использования с базой данных MySQL?

  • 0
    Я планирую сделать то же самое в ближайшем будущем. Я занимаюсь программированием на основе местоположения, я полагаю? Что за приложение?
  • 1
    Я нашел эту ссылку очень полезной: howto-use-mysql-spatial-ext.blogspot.com/2007/11/… Возможно, она немного старше, но содержит полное объяснение, включая примеры.
Показать ещё 12 комментариев
Теги:
database
database-design
mapping
maps
latitude-longitude

20 ответов

155
Лучший ответ

Используйте MySQL пространственные расширения с помощью ГИС.

  • 19
    Есть ли у вас какие-либо другие ссылки на примеры или какая-либо другая информация о том, как лучше всего начать с ними?
  • 6
    MYSQL Spatial является хорошим вариантом, но все еще имеет значительные ограничения и предостережения (по состоянию на 6). Пожалуйста, смотрите мой ответ ниже ...
Показать ещё 5 комментариев
141

Google предоставляет начало для завершения PHP/MySQL-решения для примера приложения "Store Locator" с Google Maps. В этом примере они сохраняют значения lat/lng как "Float" с длиной "10,6"

http://code.google.com/apis/maps/articles/phpsqlsearch.html

  • 11
    Google явно не понимает, как работает спецификация FLOAT: FLOAT(10,6) оставляет 4 цифры для целочисленной части координаты. И нет, знак не считается - это происходит из (не) подписанного атрибута.
  • 2
    Но если вам нужно сохранить как целые части значения из [0, 180], то их должно быть более чем достаточно, верно?
Показать ещё 10 комментариев
110

В основном это зависит от точности, необходимой для ваших местоположений. Используя DOUBLE, вы получите точность 3,5 нм. DECIMAL (8,6)/(9,6) сокращается до 16 см. FLOAT составляет 1,7 м...

В этой очень интересной таблице есть более полный список: 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

Надеюсь, что это поможет.

  • 1
    Мне нужно написать конструктивный, подробный комментарий, сосредоточенный на содержании постов, поэтому я скажу, что, наблюдая таблицу точности, приведенную на сайте Рика Джеймса, я был слегка удивлен описанием резолюции «блохи на собаке» и чувствовал, что это достойно похвалы. С технической точки зрения, это было полезное описание, которое помогло мне решить, какой тип данных использовать при сохранении координат для измерения расстояния между двумя адресами, и, @Simon, я хотел бы поблагодарить вас за обмен.
  • 0
    Дополнительная информация о точности stackoverflow.com/a/16743805/722135
77

MySQL Spatial Extensions - лучший вариант, потому что у вас есть полный список пространственных операторов и индексов в вашем распоряжении. Пространственный индекс позволит вам выполнять дистанционные вычисления очень быстро. Имейте в виду, что с 6,0 Пространственное расширение еще не завершено. Я не ставил MySQL Spatial, давая вам знать о подводных камнях, прежде чем вы слишком далеко продвигаетесь вперед.

Если вы имеете дело строго с точками и только функцией DISTANCE, это нормально. Если вам нужно делать какие-либо вычисления с помощью полигонов, линий или буферизованных точек, пространственные операторы не дают точных результатов, если вы не используете оператор "связать". См. Предупреждение в верхней части 21.5.6. Отношения, такие как содержит, внутри или пересекаются, используют MBR, а не точную форму геометрии (т.е. Эллипс рассматривается как прямоугольник).

Кроме того, расстояния в MySQL Spatial находятся в тех же единицах, что и ваша первая геометрия. Это означает, что если вы используете десятичные градусы, то ваши измерения расстояния находятся в десятичных градусах. Это очень затруднит получение точных результатов по мере того, как вы получите фуфур от экватора.

  • 26
    Повторение: MySQL Spatial Extensions не подходит для расчета расстояний большого круга между точками на поверхности земли, представленными широтой / долготой. Их функции расстояния и т. Д. Полезны только для декартовых, плоских координат.
66

Когда я сделал это для базы данных навигации, построенной из ARINC424, я провел довольно много испытаний и оглядываясь на код, я использовал DECIMAL (18,12) (на самом деле NUMERIC (18,12), потому что это был firebird).

Поплавки и удвоения не так точны и могут привести к ошибкам округления, что может быть очень плохо. Я не могу вспомнить, нашел ли я какие-либо реальные данные, которые имели проблемы, но я вполне уверен, что невозможность аккумулировать память в float или double может вызвать проблемы.

Дело в том, что при использовании градусов или радиан мы знаем диапазон значений - и дробная часть нуждается в большинстве цифр.

MySQL Spatial Extensions являются хорошей альтернативой, потому что они следуют OpenGIS Геометрическая модель. Я не использовал их, потому что мне нужно было переносить мою базу данных.

  • 2
    Спасибо, это было полезно. Чувствует себя странно, читая все эти вопросы и ответы с 2008 года, понимая, что это было уже 8 лет назад.
  • 0
    @TheSexiestManinJamaica - До IEEE 754-1985 компьютерное оборудование с плавающей точкой было хаотичным. Был даже на машине, где a*b не было равно b*a (для некоторых значений). Было много примеров вроде: 2+2 = 3.9999 . Стандарт устранил много беспорядка и был «быстро» принят практически каждым оборудованием и программным обеспечением. Таким образом, эта дискуссия действительна не только с 2008 года, но уже треть века.
36

Зависит от требуемой точности.

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

От: http://mysql.rjweb.org/doc.php/latlng

Подводя итог:

  • Наиболее точная доступная опция DOUBLE.
  • Наиболее распространенным видным типом является DECIMAL(8,6)/(9,6).

По MySQL 5.7 рассмотрите использование пространственных типов данных (SDT), в частности POINT для хранения одной координаты. До 5.7 SDT не поддерживает индексы (за исключением 5.6, когда тип таблицы - MyISAM).

Примечание:

  • 2
    Вы копируете вставленную часть предыдущего ответа и «обобщаете» что-то, что парень, который создал эту таблицу , не рекомендовал : «Как РАЗДЕЛИТЬ? Ну, MySQL очень требователен. Так что FLOAT / DOUBLE отсутствуют. DECIMAL отсутствует. Итак, мы застряли в некотором клудже. По сути, нам нужно преобразовать Lat / Lng в некоторый размер INT и использовать PARTITION BY RANGE. »И« FLOAT имеет 24 значащих бита; У DOUBLE есть 53. (Они не работают с PARTITIONing, но включены для полноты. Часто люди используют DOUBLE, не осознавая, насколько это избыточный объем и сколько места занимает.) »Просто оставьте часть SDT, которую вы написали.
  • 1
    @Armfoot Если вы посмотрите на время правок, это другой ответ, который скопирован с меня. Не то, чтобы это имело значение: я вижу переполнение стека больше «заметками для будущего меня».
Показать ещё 4 комментария
32

Основываясь на этой статье wiki http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy соответствующий тип данных в MySQL является десятичным (9,6) для хранения долготы и широты в отдельные поля.

18

Используйте DECIMAL(8,6) для широты (от 90 до -90 градусов) и DECIMAL(9,6) для долготы (от 180 до -180 градусов). 6 десятичных знаков отлично подходят для большинства приложений. Оба должны быть "подписаны", чтобы допускать отрицательные значения.

  • 0
    Тип DECIMAL предназначен для финансовых расчетов, если floor/ceil не принимаются. Обычный FLOAT значительно превосходит DECIMAL .
  • 0
    @Kondybas - Поскольку основная стоимость в базе данных - это выборка строк, разница в производительности между числами с плавающей запятой и десятичной не должна быть проблемой.
13

Не нужно далеко ходить, согласно Google Maps, лучшим является FLOAT (10,6) для lat и lng.

7

Мы храним широту/долготу X 1,000,000 в нашей базе данных оракула как ЧИСЛО, чтобы избежать ошибок округления с удвоениями.

Учитывая, что широта/долгота до шестого десятичного знака была 10-сантиметровой точностью, это было все, что нам нужно. Многие другие базы данных также хранят lat/long до шестого знака после запятой.

  • 2
    Умножение на какое-то большое число (например, на миллион) прекрасно, если у вас много данных, потому что целочисленные операции (например, индексированный поиск) выполняются намного быстрее, чем операции с плавающей запятой.
6

В совершенно другой и более простой перспективе:

  • если вы полагаетесь на Google, чтобы показывать свои карты, маркеры, полигоны, что угодно, а затем разрешить вычисления Google!
  • вы сохраняете ресурсы на своем сервере, и вы просто сохраняете широту и долготу вместе как одну строку (VARCHAR), например: " - 0000.0000001, -0000.000000000000001" (длина 35 и если число имеет более 7 десятичных цифр, то округляется);
  • Если Google вернет более 7 десятичных цифр на номер, вы можете получить эти данные, хранящиеся в вашей строке, на всякий случай, если вы хотите обнаружить некоторые бегства или микробы в будущем;
  • вы можете использовать их расстояние матрицы или их геометрия для вычисления расстояний или определение точек в определенных областях с такими же простыми вызовами: google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon))
  • существует множество "серверных" API, которые вы можете использовать (в Python, Ruby on Rails, PHP, CodeIgniter, Laravel, Yii, Zend Framework и т.д.), которые используют API Карт Google.

Таким образом вам не нужно беспокоиться об индексах и всех других проблемах, связанных с типами данных, которые могут испортить ваши координаты.

  • 0
    Не хорошо. ОП сказал, что он будет выполнять расчеты по парам широта / долгота - ваши ответы исключают
  • 4
    @ Yarin Это популярный вопрос, когда несколько (или много) людей просто нуждаются в ответе о том, как хранить координаты в соответствии со своими потребностями (многие из них могут просто использовать карты Google). Ваш отрицательный голос предполагает, что этот ответ может не помочь им ... Храня координаты в строке, они будут точно знать исходные значения, которые были предоставлены им (например, Google), что поможет им позже, если они решат развить свои Собственное приложение и выполнять на них расчеты. В то время у них все еще будут исходные необработанные данные только потому, что они не перепутали их с конверсиями.
4

Пока он не является оптимальным для всех операций, если вы делаете картографические плитки или работаете с большим количеством маркеров (точек) только с одной проекцией (например, Mercator, например, Карты Google и многие другие слабые карты), я нашли то, что я называю "Vast Coordinate System", действительно, очень удобно. В основном, вы сохраняете координаты x и y пикселя каким-то образом - увеличенным - я использую уровень масштабирования 23. Это имеет несколько преимуществ:

  • Вы делаете дорогостоящие преобразования lat/lng в пиксель пикселя меркатора один раз, а не каждый раз, когда вы обрабатываете точку
  • Получение координаты плитки из записи с учетом уровня масштабирования занимает один сдвиг вправо.
  • Получение координаты пикселя из записи занимает один правый сдвиг и побитовое значение AND.
  • Сдвиги настолько легки, что их можно делать в SQL, что означает, что вы можете сделать DISTINCT, чтобы вернуть только одну запись на пиксель, которая сократит количество записей, возвращаемых бэкэнд, что означает меньше обработка на переднем конце.

Я рассказывал обо всем этом в недавнем сообщении в блоге:  http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/

4

в зависимости от вашего приложения, я предлагаю использовать FLOAT (9,6)

пространственные ключи предоставят вам больше возможностей, но по производственным эталонам поплавки намного быстрее, чем пространственные ключи. (0,01 VS 0,001 в AVG)

  • 0
    Можете ли вы предоставить свой результат теста с деталями здесь?
3

Я очень удивлен некоторыми ответами/комментариями.

Почему бы вам не захотеть добровольно "преуменьшить" точность, а затем выполнить вычисления по худшим цифрам? Звучит глупо.

Если источник имеет 64-битную точность, то, конечно, было бы немым, чтобы вовремя исправить масштаб, например. 6 десятичных знаков и ограничить точность до 9 значащих цифр (что происходит с обычно предлагаемым десятичным форматом 9.6).

Естественно, что один хранит данные с точностью, которую имеет исходный материал. Единственной причиной снижения точности было бы ограниченное пространство для хранения.

  • Сохранить исходные данные с оригинальной точностью
  • Сохранять цифры, рассчитываемые из источника, в точности, которую выполняет расчет (например, если код приложения использует удвоение, сохраняйте результаты как удвоенные)

Десятичный 9.6-формат вызывает феномен привязки к сетке. Это должен быть последний шаг, если это вообще произойдет.

Я не приглашал бы накопленные ошибки в свое гнездо.

  • 1
    Потому что большинство инструментов и приложений GPS с точностью до 6 знаков после запятой. Бессмысленно хранить данные с большей точностью, чем то, что могут измерить инструменты gis.stackexchange.com/questions/8650/…
  • 1
    @ Ярин Да, действительно, но вы говорите об измерениях и GPS, которые не упомянуты в вопросе. Скорее всего, существуют более точные цифры. Но давайте рассмотрим GPS; скажем, исходный набор данных с 64-битными числами с плавающей точкой, который уже содержит неточность. 6 десятичных знаков означает привязку широты к ближайшим приблизительно 11 сантиметрам. Следовательно, теперь, сохраняя только данные (с 6 десятичными знаками), вы открываете себя для потенциальной погрешности 22 см (если изначально тоже 11 см). Добровольно, вероятно, для этого нужно выполнить 64-разрядный расчет, прежде чем, возможно, сохранить в 3-й раз - теперь окно с погрешностью 33 см, + -16 см. Звучит глупо, имхо.
Показать ещё 2 комментария
3

MySQL использует double для всех поплавков... Поэтому используйте тип double. Использование float приведет к непредсказуемым округленным значениям в большинстве ситуаций.

  • 1
    MySQL выполняет операции в DOUBLE . MySQL позволяет хранить данные как 4-байтовый FLOAT или 8-байтовый DOUBLE . Таким образом, при сохранении выражения в столбце FLOAT возможна потеря точности.
3

Пространственные функции в PostGIS гораздо более функциональны (т.е. не ограничены операциями BBOX), чем функции пространственных функций MySQL. Проверьте это: текст ссылки

2

TL; DR

Используйте FLOAT (8,5), если вы не работаете в НАСА/военных и не создаете навигационные системы самолетов.


Чтобы полностью ответить на ваш вопрос, вам нужно рассмотреть несколько вещей:

Формат

  • градусы минут секунд: 40 ° 26 '46 "N 79 ° 58' 56" Вт
  • градусы десятичных минут: 40 ° 26,767 'N 79 ° 58,933' W
  • десятичные степени 1: 40,446 ° N 79,982 ° W
  • десятичные степени 2: -32.60875, 21.27812
  • Какой-то другой домашний формат? Никто не запрещает вам создавать свою домашнюю систему координат и хранить ее как заголовок и расстояние от вашего дома. Это может иметь смысл для некоторых конкретных проблем, над которыми вы работаете.

Таким образом, первая часть ответа будет заключаться в том, что вы можете сохранить координаты в формате, используемом вашим приложением, чтобы избежать постоянных преобразований взад и вперед и упростить SQL-запросы.

Скорее всего, вы используете Google Maps или OSM для отображения своих данных, а GMaps используют формат "десятичной степени 2". Поэтому сохранять координаты в том же формате проще.

точность

Затем вы хотите определить нужную точность. Конечно, вы можете хранить координаты, такие как "-32.608697550570334,21.278081997935146", но вы когда-нибудь заботились о миллиметрах при навигации к точке? Если вы не работаете в НАСА и не выполняете траектории спутников или ракет или самолетов, вы должны быть в порядке с точностью до нескольких метров.

Обычно используемый формат составляет 5 цифр после точек, что дает вам точность 50 см.

Пример: расстояние 1 см между X, 21.278081 8 и X, 21.278081 9. Таким образом, 7 цифр после точки дают вам точность 1/2 см и 5 цифр после точки дают вам точность в 1/2 метра (поскольку минимальное расстояние между различными точками равно 1 м, поэтому ошибка округления не может превышать половины). Для большинства гражданских целей этого должно быть достаточно.

градус десятичных минут (40 ° 26,767 'N 79 ° 58,933' W) дает вам точно такую же точность, как 5 цифр после точки

Экономичное пространство

Если вы выбрали десятичный формат, то ваша координата - это пара (-32.60875, 21.27812). Очевидно, достаточно 2 x (1 бит для знака, 2 цифры для степеней и 5 цифр для экспоненты).

Поэтому я хотел бы поддержать Alix Axel от комментариев, говорящих, что предложение Google хранить его в FLOAT (10,6) действительно является дополнительным, потому что вам не нужны 4 цифры для основной части (поскольку знак разделен и широта ограничена до 90 и долгота ограничивается 180). Вы можете легко использовать FLOAT (8,5) для точности 1/2 м или FLOAT (9,6) для точности 50/2 см. Или вы даже можете хранить lat и long в разделенных типах, потому что FLOAT (7,5) достаточно для lat. См. Ссылку на типы ссылок на MySQL. Любой из них будет как обычный FLOAT и равен 4 байтам в любом случае.

Обычно пространство не является проблемой в настоящее время, но если вы хотите по-настоящему оптимизировать хранилище по какой-либо причине (Отказ от ответственности: не делайте предварительной оптимизации), вы можете сжать lat (не более 91 000 значений + знак) + long (нет более 181 000 значений + знак) до 21 бит, что значительно меньше 2xFLOAT (8 байтов == 64 бит)

0
  1. Широты варьируются от -90 до +90 (градусы), поэтому DECIMAL (10, 8) подходит для этого

  2. долготы варьируются от -180 до +180 (градусы), поэтому вам нужно DECIMAL (11, 8).

Примечание. Первое число - это общее количество сохраненных цифр, а второе - число после десятичной точки.

Короче: lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL

-3

Расчеты Lat Long требуют точности, поэтому используйте тип десятичного типа и сделайте точность не менее чем на 2 выше, чем число, которое вы будете хранить для выполнения математических вычислений. Я не знаю о моих типах данных sql, но в SQL-сервере люди часто используют float или real вместо десятичного числа и попадают в неприятности, потому что это оценочные числа, которые не являются реальными. Поэтому просто убедитесь, что тип данных, который вы используете, является истинным десятичным типом, а не плавающим десятичным типом, и вы должны быть в порядке.

  • 1
    и float, и десятичные типы имеют свое место. как правило, числа с плавающей запятой означают физические переменные, а десятичные дроби - для счетных объектов (в основном деньги). я не понимаю, почему вы бы предпочли десятичную для широты / долготы
  • 1
    Я также думаю, что float подходит для lat / long. По крайней мере, на SQL Server (4 байта, 7 цифр).
Показать ещё 3 комментария
-4

A FLOAT должен предоставить вам всю необходимую точность и быть лучше для функций сравнения, чем хранить каждую координату в виде строки или тому подобного.

Если ваша версия MySQL более ранняя, чем 5.0.3, вам, возможно, придется учитывать некоторые ошибки сравнения с плавающей запятой.

До MySQL 5.0.3 столбцы DECIMAL хранят значения с точной точностью, потому что они представлены в виде строк, но вычисления значений DECIMAL выполняются с использованием операций с плавающей запятой. Начиная с версии 5.0.3 MySQL выполняет операции DECIMAL с точностью до 64 десятичных цифр, что должно решить наиболее распространенные проблемы неточности, когда дело доходит до столбцов DECIMAL.

  • 2
    Вам нужен реальный координаты широты / долготы для легкой математики. Представьте себе удобство чего-то вроде эквивалента «выбрать * из магазинов, где расстояние (stores.location, mylocation) <5 миль»
  • 1
    Раньше я не слышал о пространственных расширениях, это звучит очень удобно, поскольку ранее он работал над унаследованным приложением, которое выполняет довольно мало вычислений, связанных с географией, и должен это проверить.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню