什么MySQL数据类型应该用于纬度/经度与8位小数?

我正在处理地图数据,Latitude/Longitude扩展到小数点后8位。例如:

Latitude 40.71727401
Longitude -74.00898606

我在谷歌Document中看到

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

然而,他们的小数点后只到6 我应该使用FLOAT(10, 8)还是有其他方法来存储这些数据,以便它是精确的。它将用于地图计算。谢谢!< / p >

267182 次浏览

MySQL支持空间数据类型,而Point是一个可以使用的单值类型。例子:

CREATE TABLE `buildings` (
`coordinate` POINT NOT NULL,
/* Even from v5.7.5 you can define an index for it */
SPATIAL INDEX `SPATIAL` (`coordinate`)
) ENGINE=InnoDB;


/* then for insertion you can */
INSERT INTO `buildings`
(`coordinate`)
VALUES
(POINT(40.71727401 -74.00898606));

此外,你会看到float值是四舍五入的。

// e.g: given values 41.0473112,29.0077011


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


您可以将数据类型设置为有符号整数。当你存储坐标到SQL时,你可以设置为lat*10000000和long*10000000。当你选择距离/半径时,你会把存储坐标划分为10000000。我用300K行进行了测试,查询响应时间很好。(2 * 2.67GHz CPU, 2gb RAM, MySQL 5.5.49)

在rails上使用迁移ruby

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

不要使用浮动…它会环绕你的坐标,导致一些奇怪的现象。

使用十进制

自从提出这个问题以来,MySQL现在已经支持空间数据类型了。所以目前接受的答案是正确的,但如果你正在寻找额外的功能,如找到给定多边形内的所有点,那么使用POINT数据类型。

签出Mysql文档中的地理空间数据类型空间分析功能

在laravel中使用十进制列类型进行迁移

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

看到可用列类型

我相信在MySQL中存储Lat/Lng的最好方法是有一个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));
CREATE TABLE your_table_name (
lattitude  REAL,
longitude  REAL
)

也可以考虑在你的lat, long声明中添加进一步的验证:

CREATE TABLE your_table_name (
lattitude  REAL CHECK(lattitude IS NULL OR (lattitude >= -90 AND lattitude <= 90)),
longitude  REAL CHECK(longitude IS NULL OR (longitude >= -180 AND longitude <= 180))
)
< p >解释: https://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html < / p >

小数点后6位的精度约为16cm,这意味着两个物体之间的距离小于16cm时,它们具有相同的纬度和lng。

同样,在mariadb/mysql中,如果我们有大量的数据用于索引,使用float/double是不理想的,而Point数据类型是数据大小的开销。最好使用十进制或将latlong转换为INT。

使用小数点后6位的小数是一个很好的选择,因为我们可以忽略转换,我们只有16cm的误差,经度在-180到180之间,因此需要比纬度多1位,它在-90到90度之间:

Lat DECIMAL(8,6)
Lng DECIMAL(9,6)

我们可以延伸到小数点后8位:

Lat DECIMAL(10,8)
Lng DECIMAL(11,8)

MySQL reference

Mariadb reference

你应该简单地使用varchar (20)