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

Я работаю с данными карты, а Latitude/Longitude - до 8 знаков после запятой. Например:

Latitude 40.71727401
Longitude -74.00898606

Я видел в Документ Google который использует:

lat FLOAT( 10, 6 ) NOT NULL,  
lng FLOAT( 10, 6 ) NOT NULL

однако их десятичные разряды идут только до 6.
Должен ли я использовать FLOAT(10, 8) или есть другой метод, который следует учитывать для хранения этих данных, чтобы он был точным. Он будет использоваться с расчетами карты. Спасибо!

Ответ 1

DECIMAL - это тип данных MySQL для точной арифметики. В отличие от FLOAT его точность фиксируется для любого размера числа, поэтому, используя его вместо FLOAT, вы можете избежать ошибок точности при выполнении некоторых вычислений. Если бы вы просто хранили и извлекали числа без расчета, то на практике FLOAT был бы безопасен, хотя нет никакого вреда в использовании DECIMAL. С расчетами FLOAT по-прежнему в основном нормально, но абсолютно уверен в 8d.p. точность вы должны использовать DECIMAL.

Широта варьируется от -90 до +90 (градусов), поэтому для этого подходит DECIMAL (10, 8), но долготы колеблются от -180 до +180 (в градусах), поэтому вам нужен DECIMAL (11, 8). Первое число - это общее количество сохраненных цифр, а второе - число после десятичной точки.

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

В этом объясняется, как MySQL работает с типами данных с плавающей запятой.

Ответ 2

Кроме того, вы увидите, что значения float округлены.

// e.g: given values 41.0473112,29.0077011

float(11,7) | decimal(11,7)
---------------------------
41.0473099  | 41.0473112
29.0077019  | 29.0077011

Ответ 3

Вы можете установить свой тип данных как целое число со знаком. Когда вы храните координаты в SQL, вы можете установить как lat * 10000000 и long * 10000000. И когда вы выбираете с расстоянием/радиусом, вы разделите координаты хранения на 10000000. Я тестировал его с 300K строк, время ответа на запрос хорошее. (2 x 2,67 ГГц процессор, 2 ГБ оперативной памяти, MySQL 5.5.49)

Ответ 4

Не используйте float... Он будет округлять ваши координаты, что приведет к некоторым странным событиям.

Использовать десятичную

Ответ 5

MySQL теперь поддерживает пространственные типы данных, так как этот вопрос был задан. Таким образом, текущий принятый ответ не является неправильным, но если вы ищете дополнительные функциональные возможности, такие как поиск всех точек в данном многоугольнике, используйте тип данных POINT.

Ознакомьтесь с документами Mysql о типах геопространственных данных и функциях пространственного анализа

Ответ 6

в laravel для переноса используется тип десятичного столбца

$table->decimal('latitude', 10, 8);
$table->decimal('longitude', 11, 8);

для получения дополнительной информации см. доступный тип столбца

Ответ 7

Лучший способ в моем случае - сохранить координаты как DOUBLE.

lat DOUBLE NOT NULL,  
lng DOUBLE NOT NULL

Он сохранит все значение без округления.

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

Ответ 8

Использование миграции рубинов на рельсах

class CreateNeighborhoods < ActiveRecord::Migration[5.0]
  def change
    create_table :neighborhoods do |t|
      t.string :name
      t.decimal :latitude, precision: 15, scale: 13
      t.decimal :longitude, precision: 15, scale: 13
      t.references :country, foreign_key: true
      t.references :state, foreign_key: true
      t.references :city, foreign_key: true

      t.timestamps
    end
  end
end

Ответ 9

Я считаю, что лучший способ хранить Lat/Lng в MySQL - это иметь столбец POINT (2D-тип данных) с индексом SPATIAL.

CREATE TABLE 'cities' (
  'zip' varchar(8) NOT NULL,
  'country' varchar (2) GENERATED ALWAYS AS (SUBSTRING('zip', 1, 2)) STORED,
  'city' varchar(30) NOT NULL,
  'centre' point NOT NULL,
  PRIMARY KEY ('zip'),
  KEY 'country' ('country'),
  KEY 'city' ('city'),
  SPATIAL KEY 'centre' ('centre')
) ENGINE=InnoDB;


INSERT INTO 'cities' ('zip', 'city', 'centre') VALUES
('CZ-10000', 'Prague', POINT(50.0755381, 14.4378005));