关于MYSQL 时间类型存储在数据库里是啥类型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于MYSQL 时间类型存储在数据库里是啥类型相关的知识,希望对你有一定的参考价值。

参考技术A mysql中经常用来存储日期的数据类型有三种:Date、Datetime、Timestamp。

Date数据类型:用来存储没有时间的日期。Mysql获取和显示这个类型的格式为“YYYY-MM-DD”。支持的时间范围为“1000-00-00”到“9999-12-31”。

Datetime类型:存储既有日期又有时间的数据。存储和显示的格式为 “YYYY-MM-DD HH:MM:SS”。支持的时间范围是“1000-00-00 00:00:00”到“9999-12-31 23:59:59”。

Timestamp类型:也是存储既有日期又有时间的数据。存储和显示的格式跟Datetime一样。支持的时间范围是“1970-01-01 00:00:01”到“2038-01-19 03:14:07”。

所有不符合上面所述格式的数据都会被转换为相应类型的0值。(0000-00-00或者0000-00-00 00:00:00)
参考技术B

MySQL 数据类型细分下来,大概有以下几类:

    数值,典型代表为 tinyint,int,bigint

    浮点/定点,典型代表为 float,double,decimal 以及相关的同义词

    字符串,典型代表为 char,varchar

    时间日期,典型代表为 date,datetime,time,timestamp

    二进制,典型代表为 binary,varbinary

    位类型

    枚举类型

    集合类型

    大对象,比如 text,blob

    json 文档类型

    一、数值类型(不是数据类型,别看错了)如果用来存放整数,根据范围的不同,选择不同的类型。


    以上是几个整数选型的例子。整数的应用范围最广泛,可以用来存储数字,也可以用来存储时间戳,还可以用来存储其他类型转换为数字后的编码,如 IPv4 等。示例 1用 int32 来存放 IPv4 地址,比单纯用字符串节省空间。表 x1,字段 ipaddr,利用函数 inet_aton,检索的话用函数 inet_ntoa。

    查看磁盘空间占用,t3 占用最大,t1 占用最小。所以说如果整数存储范围有固定上限,并且未来也没有必要扩容的话,建议选择最小的类型,当然了对其他类型也适用。root@ytt-pc:/var/lib/mysql/3305/ytt# ls -sihl总用量 3.0G3541825 861M -rw-r----- 1 mysql mysql 860M 12月 10 11:36 t1.ibd3541820 989M -rw-r----- 1 mysql mysql 988M 12月 10 11:38 t2.ibd3541823 1.2G -rw-r----- 1 mysql mysql 1.2G 12月 10 11:39 t3.ibd

    二、浮点数 / 定点数先说 浮点数,float 和 double 都代表浮点数,区别简单记就是 float 默认占 4 Byte。float(p) 中的 p 代表整数位最小精度。如果 p > 24 则直接转换为 double,占 8 Byte。p 最大值为 53,但最大值存在计算不精确的问题。再说 定点数,包括 decimal 以及同义词 numeric,定点数的整数位和小数位分别存储,有效精度最大不能超过 65。所以区别于 float 的在于精确存储,必须需要精确存储或者精确计算的最好定义为 decimal 即可。示例 3创建一张表 y1,分别给字段 f1,f2,f3 不同的类型。mysql-(ytt/3305)->create table y1(f1 float,f2 double,f3 decimal(10,2));Query OK, 0 rows affected (0.03 sec)


    三、字符类型字符类型和整形一样,用途也很广。用来存储字符、字符串、MySQL 所有未知的类型。可以简单说是万能类型!


    char(10) 代表最大支持 10 个字符存储,varhar(10) 虽然和 char(10) 可存储的字符数一样多,不同的是 varchar 类型存储的是实际大小,char 存储的理论固定大小。具体的字节数和字符集相关。示例 4例如下面表 t4 ,两个字段 c1,c2,分别为 char 和 varchar。mysql-(ytt/3305)->create table t4 (c1 char(20),c2 varchar(20));Query OK, 0 rows affected (0.02 sec)


    所以在 char 和 varchar 选型上,要注意看是否合适的取值范围。比如固定长度的值,肯定要选择 char;不确定的值,则选择 varchar。


    四、日期类型日期类型包含了 date,time,datetime,timestamp,以及 year。year 占 1 Byte,date 占 3 Byte。 


    time,timestamp,datetime 在不包含小数位时分别占用 3 Byte,4 Byte,8 Byte;小数位部分另外计算磁盘占用,见下面表格。

    请点击输入图片描述

    请点击输入图片描述

    请点击输入图片描述

    注意:timestamp 代表的时间戳是一个 int32 存储的整数,取值范围为 '1970-01-01 00:00:01.000000' 到 '2038-01-19 03:14:07.999999';datetime 取值范围为 '1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999'。 

    综上所述,日期这块类型的选择遵循以下原则:

    1. 如果时间有可能超过时间戳范围,优先选择 datetime。2. 如果需要单独获取年份值,比如按照年来分区,按照年来检索等,最好在表中添加一个 year 类型来参与。3. 如果需要单独获取日期或者时间,最好是单独存放,而不是简单的用 datetime 或者 timestamp。后面检索时,再加函数过滤,以免后期增加 SQL 编写带来额外消耗。

    4. 如果有保存毫秒类似的需求,最好是用时间类型自己的特性,不要直接用字符类型来代替。MySQL 内部的类型转换对资源额外的消耗也是需要考虑的。

    示例 5

    建立表 t5,对这些可能需要的字段全部分离开,这样以后写 SQL 语句的时候就很容易了。

    当然了,这种情形占用额外的磁盘空间。如果想在易用性与空间占用量大这两点来折中,可以用 MySQL 的虚拟列来实时计算。比如假设 c5 字段不存在,想要得到 c5 的结果。mysql-(ytt/3305)->alter table t5 drop c5, add c5 year generated always as (year(c1)) virtual;Query OK, 1 row affected (2.46 sec)Records: 1  Duplicates: 0  Warnings: 0



    五、二进制类型

    binary 和 varbinary 对应了 char 和 varchar 的二进制存储,相关的特性都一样。不同的有以下几点:

    binary(10)/varbinary(10) 代表的不是字符个数,而是字节数。

    行结束符不一样。char 的行结束符是 \\0,binary 的行结束符是 0x00。

    由于是二进制存储,所以字符编码以及排序规则这类就直接无效了。

    示例 6

    来看这个 binary 存取的简单示例,还是之前的变量 @a。

    切记!这里要提前计算好 @a 占用的字节数,以防存储溢出。


    六、位类型

    bit 为 MySQL 里存储比特位的类型,最大支持 64 比特位, 直接以二进制方式存储,一般用来存储状态类的信息。比如,性别,真假等。具有以下特性:

    1. 对于 bit(8) 如果单纯存放 1 位,左边以 0 填充 00000001。2. 查询时可以直接十进制来过滤数据。3. 如果此字段加上索引,MySQL 不会自己做类型转换,只能用二进制来过滤。

    示例 7

    创建表 c1, 字段性别定义一个比特位。mysql-(ytt/3305)->create table c1(gender bit(1));Query OK, 0 rows affected (0.02 sec)



    mysql-(ytt/3305)->select cast(gender as unsigned)  'f1' from c1;+------+| f1   |+------+|    0 ||    1 |+------+2 rows in set (0.00 sec)


    过滤数据也一样,二进制或者直接十进制都行。mysql-(ytt/3305)->select conv(gender,16,10) as gender \\   -> from c1 where gender = b'1'; +--------+| gender |+--------+| 1      |+--------+1 row in set (0.00 sec)    mysql-(ytt/3305)->select conv(gender,16,10) as gender \\    -> from c1 where gender = '1';+--------+| gender |+--------+| 1      |+--------+1 row in set (0.00 sec)


    其实这样的场景,也可以定义为 char(0),这也是类似于 bit 非常优化的一种用法。

    mysql-(ytt/3305)->create table c2(gender char(0));Query OK, 0 rows affected (0.03 sec)


    那现在我给表 c1 简单的造点测试数据。

    mysql-(ytt/3305)->select count(*) from c1;+----------+| count(*) |+----------+| 33554432 |+----------+1 row in set (1.37 sec)


    把 c1 的数据全部插入 c2。

    mysql-(ytt/3305)->insert into c2 select if(gender = 0,'',null) from c1;Query OK, 33554432 rows affected (2 min 18.80 sec)Records: 33554432  Duplicates: 0  Warnings: 0


    两张表的磁盘占用差不多。root@ytt-pc:/var/lib/mysql/3305/ytt# ls -sihl总用量 1.9G4085684 933M -rw-r----- 1 mysql mysql 932M 12月 11 10:16 c1.ibd4082686 917M -rw-r----- 1 mysql mysql 916M 12月 11 10:22 c2.ibd


    检索方式稍微有些不同,不过效率也差不多。所以说,字符类型不愧为万能类型。


    七、枚举类型

    枚举类型,也即 enum。适合提前规划好了所有已经知道的值,且未来最好不要加新值的情形。枚举类型有以下特性:

    1. 最大占用 2 Byte。2. 最大支持 65535 个不同元素。3. MySQL 后台存储以下标的方式,也就是 tinyint 或者 smallint 的方式,下标从 1 开始。4. 排序时按照下标排序,而不是按照里面元素的数据类型。所以这点要格外注意。

    示例 8

    创建表 t7。mysql-(ytt/3305)->create table t7(c1 enum('mysql','oracle','dble','postgresql','mongodb','redis','db2','sql server'));Query OK, 0 rows affected (0.03 sec)



    八、集合类型

    集合类型 SET 和枚举类似,也是得提前知道有多少个元素。SET 有以下特点:

    1. 最大占用 8 Byte,int64。2. 内部以二进制位的方式存储,对应的下标如果以十进制来看,就分别为 1,2,4,8,...,pow(2,63)。3. 最大支持 64 个不同的元素,重复元素的插入,取出来直接去重。4. 元素之间可以组合插入,比如下标为 1 和 2 的可以一起插入,直接插入 3 即可。

    示例 9

    定义表 c7 字段 c1 为 set 类型,包含了 8 个值,也就是下表最大为 pow(2,7)。

    mysql-(ytt/3305)->create table c7(c1 set('mysql','oracle','dble','postgresql','mongodb','redis','db2','sql server'));Query OK, 0 rows affected (0.02 sec)


    插入 1 到 128 的所有组合。

    mysql-(ytt/3305)->INSERT INTO c7WITH RECURSIVE ytt_number (cnt) AS (        SELECT 1 AS cnt        UNION ALL        SELECT cnt + 1        FROM ytt_number        WHERE cnt < pow(2, 7)    )SELECT *FROM ytt_number;Query OK, 128 rows affected (0.01 sec)Records: 128  Duplicates: 0  Warnings: 0

    九、数据类型在存储函数中的用法

    函数里除了显式声明的变量外,默认 session 变量的数据类型很弱,随着给定值的不同随意转换。

    示例 10

    定义一个函数,返回两个给定参数的乘积。定义里有两个变量,一个是 v_tmp 显式定义为 int64,另外一个 @vresult 随着给定值的类型随意变换类型。


    简单调用下。

    mysql-(ytt/3305)->select ytt_sample_data_type(1111,222) 'result';+--------------------------+| result                   |+--------------------------+| The result is: '246642'. |+--------------------------+1 row in set (0.00 sec)


    总结

    本篇把 MySQL 基本的数据类型做了简单的介绍,并且用了一些容易理解的示例来梳理这些类型。我们在实际场景中,建议选择适合最合适的类型,不建议所有数据类型简单的最大化原则。比如能用 varchar(100),不用 varchar(1000)。

在 MySQL 数据库中存储纬度/经度时使用的理想数据类型是啥?

【中文标题】在 MySQL 数据库中存储纬度/经度时使用的理想数据类型是啥?【英文标题】:What is the ideal data type to use when storing latitude / longitude in a MySQL database?在 MySQL 数据库中存储纬度/经度时使用的理想数据类型是什么? 【发布时间】:2010-09-14 15:03:28 【问题描述】:

考虑到我将在纬度/经度对上执行计算,哪种数据类型最适合与 MySQL 数据库一起使用?

【问题讨论】:

我发现这个链接非常有用:howto-use-mysql-spatial-ext.blogspot.com/2007/11/… 它可能有点旧,但它包含一个完整的解释,包括示例。 恕我直言,这里的大多数人都不明白发生了什么。只要应用程序代码接触一个数字,只要使用双精度数(大多数情况下都是这样),该数字最多变成双精度数。然后用一百万个小数存储它不会有任何好处。使用有限个小数(例如6)破坏该精度的一部分并添加累积错误每次将其重新写入数据库时。 double 携带 ca 16 个有效数字,可能是所有小数。随着时间的推移,废弃其中的 10 个会产生累积的错误。出于某种原因,它是“浮点”。续。 续:当存储从外部来源获取的、未更改的且第一次作为源材料的数字时,6 位小数可能是可以的。但是,如果对它执行一次计算并再次存储它,那么通过强制执行特定的十进制格式来删除部分精度是愚蠢。仅在服务器内部执行计算可能会有所不同(服务器可能会或可能不会在内部使用除 double 之外的其他东西),并且在 c 的应用程序计算中使用比 double 更差的数字表示同样减少了对存储精度的需求。 续:如果服务器以 更高 精度存储数字,尽管声称“9.6”(我不知道它是否确实如此) ),那么所有这些都不重要,格式纯粹是为了方便 - 与精度问题无关。但是,如果服务器实际上使用该格式将任何数字四舍五入为 6 位小数精度,我不会感到惊讶。 续:最后:对于 lat,lon's,第 6 位小数是 捕捉 到 ca 的问题。 11 厘米网格。每次读取(触摸)、计算和存储时,使用 6 位小数,将有一个新的捕捉(= 累积误差)。如果所有的错误都发生在同一个方向,就会出现一个big错误。如果对其执行临时乘法(例如,放大,然后减去和缩小),它可能会变得更大。没有好的理由,不要放弃精度! 【参考方案1】:

在 GIS 中使用 MySQL 的 spatial extensions。

【讨论】:

MYSQL Spatial 是一个不错的选择,但仍然有很大的限制和警告(截至 6)。请在下面查看我的答案... @James Schek 是对的。此外,MySQL 使用欧几里得几何进行所有计算,因此它并不代表 lat/lng 的实际用例。 仅供参考; Mysql 仅支持 *.myisam 表的空间索引,即 ISAM 引擎。链接:dev.mysql.com/doc/refman/5.0/en/creating-spatial-indexes.html 看这篇文章最后更新部分:mysqlserverteam.com/mysql-5-7-and-gis-an-example 这个答案怎么会得到这么多票,单行答案没有例子!【参考方案2】:

基本上,这取决于您的位置所需的精度。使用 DOUBLE,您将获得 3.5nm 的精度。 DECIMAL(8,6)/(9,6) 下降到 16 厘米。 FLOAT 是 1.7m...

这个非常有趣的表有一个更完整的列表: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

希望这会有所帮助。

【讨论】:

我需要针对帖子的内容写一篇建设性的、详细的评论,所以我会说,在观察 Rick James 网站提供的准确度表的同时,我对这个决议感到有点好笑描述“狗身上的跳蚤”,觉得值得称赞。从技术上讲,这是一个有用的描述,它帮助我决定在存储坐标以测量两个地址之间的距离时使用什么数据类型,@Simon,我要感谢你的分享。 FWIW,该链接对“SMALLINT scaled”的使用效率极低。 Oguzhan's answer 是在 4 字节有符号整数中存储小数点后 7 位的 long/lat 的好方法。小尺寸 (4B) 中的高精度 (~1cm)。 字节列准确吗? MySQL reference 说 DOUBLE 是 8 个字节。 要在这里回答我自己的问题,我猜他们已经将每种类型的字节数加倍以考虑纬度 + 经度(即2 doubles == 16 bytes)。【参考方案3】:

Google 为带有 Google 地图的示例“商店定位器”应用程序提供了一个从头到尾的 PHP/MySQL 解决方案。在此示例中,它们将 lat/lng 值存储为“Float”,长度为“10,6”

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

【讨论】:

Google 显然不了解 FLOAT 规范的工作原理:FLOAT(10,6) 为坐标的整数部分留下 4 位数字。不,符号不算数 - 它来自 (un)signed 属性。 但是,如果您需要将 [0, 180] 中的值存储为整数部分,应该就足够了,对吧? @AlixAxel 我认为谷歌知道它在做什么。因为它声明:“使用 Google 地图当前的缩放功能,您应该只需要小数点后 6 位精度。这将使字段存储小数点后 6 位,再加上小数点前最多 4 位,例如 -123.456789 度。"。如果选中 unsigned,则模式将为 1234,567890。所以没问题。 @AlixAxel 他正在数序列中的数字;不使用实际坐标... 对 Laravel 使用数据类型 Double【参考方案4】:

MySQL 的空间扩展是最佳选择,因为您可以使用空间运算符和索引的完整列表。空间索引将允许您非常快速地执行基于距离的计算。请记住,从 6.0 开始,空间扩展仍然不完整。我并不是要贬低 MySQL Spatial,只是让你在你走得太远之前知道其中的陷阱。

如果您严格处理点并且只处理 DISTANCE 函数,这很好。如果您需要使用多边形、线或缓冲点进行任何计算,除非您使用“相关”运算符,否则空间运算符不会提供准确的结果。请参阅21.5.6 顶部的警告。包含、内部或相交等关系使用的是 MBR,而不是确切的几何形状(即椭圆被视为矩形)。

此外,MySQL Spatial 中的距离与您的第一个几何图形的单位相同。这意味着如果您使用十进制度,那么您的距离测量值是十进制度。当您远离赤道时,这将很难获得准确的结果。

【讨论】:

重申:MySQL 空间扩展不适用于计算地球表面上由纬度/经度表示的点之间的大圆距离。它们的距离函数等仅对笛卡尔、平面、坐标有用。 上面评价很高的笔记似乎已经过时几年了。从 mysql 5.7 开始,ST_Distance_Sphere 可以做到这一点。【参考方案5】:

当我为从 ARINC424 构建的导航数据库执行此操作时,我进行了大量测试并回顾代码,我使用了 DECIMAL(18,12)(实际上是 NUMERIC(18,12),因为它是 firebird )。

浮点数和双精度数不那么精确,可能会导致舍入错误,这可能是一件非常糟糕的事情。我不记得我是否发现任何有问题的真实数据 - 但我相当确定无法准确存储在浮点数或双精度数中可能会导致问题

关键是,当使用度数或弧度时,我们知道值的范围 - 小数部分需要最多的数字。

MySQL Spatial Extensions 是一个不错的选择,因为它们关注The OpenGIS Geometry Model。我没有使用它们,因为我需要保持我的数据库可移植。

【讨论】:

谢谢,这很有帮助。从 2008 年开始阅读所有这些问题和答案,感觉很奇怪,因为这已经是 8 年前了。 @TheSexiestManinJamaica - 在 IEEE 754-1985 之前,计算机浮点硬件是混乱的。甚至在机器上a*b 不等于b*a(对于某些值)。有很多例子有点像:2+2 = 3.9999。该标准清理了很多混乱,并被几乎所有硬件和软件“迅速”采用。因此,这种讨论是有效的,不仅是从 2008 年开始,而且已经持续了三分之一个世纪。【参考方案6】:

取决于您需要的精度。

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 开始,考虑使用Spatial Data Types (SDT),特别是POINT 来存储单个坐标。在 5.7 之前,SDT 不支持索引(表类型为 MyISAM 时,5.6 除外)。

注意:

使用POINT类时,存储坐标的参数顺序必须为POINT(latitude, longitude)。 creating a spatial index 有一个特殊的语法。 使用 SDT 的最大好处是您可以访问Spatial Analyses Functions,例如计算两点之间的距离 (ST_Distance) 并确定一个点是否包含在另一个区域内 (ST_Contains)。

【讨论】:

您复制粘贴了先前答案的一部分并“总结”了创建该表的人不推荐的内容:«如何分区?嗯,MySQL 很挑剔。所以 FLOAT/DOUBLE 出来了。十进制已出。所以,我们陷入了一些混乱。本质上,我们需要将 Lat/Lng 转换为某种大小的 INT 并使用 PARTITION BY RANGE。» AND «FLOAT 有 24 个有效位; DOUBLE 有 53 个。(它们不与 PARTITIONing 一起使用,但为了完整性而包含在内。通常人们在使用 DOUBLE 时没有意识到它有多大的杀伤力,以及它占用了多少空间。)» 离开你写的 SDT 部分。 @Armfoot 如果您查看编辑时间,这是从我那里复制的另一个答案。没关系:我看到 Stack Overflow 更像是“为未来的我做的笔记”。 不,他没有从您那里复制,他只是像您从他在 2014 年引用的链接中一样粘贴表格(您的帖子来自 2015 年)。顺便说一句,我认为您在链接 Spatial 数据类型时拼错了“Special”。您编写的这部分实际上对想要开始使用它们的人很有用,如果您添加更多示例,例如 CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g)) ENGINE=MyISAM; 和有关 SDT 限制的警告,例如 James mentioned,也许您的答案会更简洁准确地帮助其他人人也是…… @Gajus - 很荣幸你们两个找到了我的文件! (不,我不知道跳蚤有多大,但我觉得它会引起别人的注意。) 使用POINT类时,存储坐标的参数顺序必须是POINT(longitude/X, latitude/Y)。【参考方案7】:

基于此 wiki 文章 http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy MySQL 中合适的数据类型是 Decimal(9,6),用于存储经度和纬度 单独的字段。

【讨论】:

【参考方案8】:

使用DECIMAL(8,6) 表示纬度(90 到 -90 度),使用 DECIMAL(9,6) 表示经度(180 到 -180 度)。 6 位小数适用于大多数应用程序。两者都应该“签名”以允许负值。

【讨论】:

DECIMAL 类型用于不接受 floor/ceil 的财务计算。普通的FLOAT 明显优于DECIMAL @Kondybas - 由于数据库中的主要成本是获取行,因此浮点数和十进制数之间的性能差异应该不是问题。【参考方案9】:

不用走太远,根据谷歌地图,lat 和 lng 最好是 FLOAT(10,6)。

【讨论】:

你从哪里得到这些我找不到的信息?以防万一发生变化。 @webfacer,这里是“在 MySQL 中创建表”部分:developers.google.com/maps/documentation/javascript/… 例如lat FLOAT( 10, 6 ) NOT NULL,lng FLOAT( 10, 6 ) NOT NULL @webfacer,从mysql 8.0.17 开始,FLOAT 语法似乎已被弃用。 Mysql 现在建议只使用FLOAT 不带任何精度参数dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html 和dev.mysql.com/doc/refman/5.5/en/floating-point-types.html 而且,MySQL 总是忽略括号中的数字,这些数字可以选择性地装饰 FLOAT 和 DOUBLE 声明。【参考方案10】:

我们在 oracle 数据库中将纬度/经度 X 1,000,000 存储为 NUMBERS 以避免双精度数的舍入错误。

考虑到小数点后 6 位的纬度/经度精度为 10 厘米,这正是我们所需要的。许多其他数据库也将 lat/long 存储到小数点后 6 位。

【讨论】:

如果您有大量数据,则乘以某个大数(例如一百万)非常好,因为整数运算(例如索引检索)比浮点数快得多。 @KaitlinDuckSherwood - 位就是位 - 我不知道 32 位浮点数的检索(索引或其他方式)比 32 位整数慢的任何原因。如今,即使是浮动数学也足够快,不会成为问题。尽管如此,我同意将隐含乘数与整数一起使用的评论:它最大限度地提高了 32 位的精度。随着技术的进步,有点面向未来。【参考方案11】:

从一个完全不同的更简单的角度来看:

如果您依靠 Google 来显示您的地图、标记、多边形等,那么请让 Google 来完成计算! 您将资源保存在您的服务器上,您只需将纬度和经度一起存储为单个字符串 (VARCHAR),例如:“-0000.0000001,-0000.000000000000001”(长度为 35,如果一个数字有超过 7 个十进制数字,那么它被四舍五入); 如果 Google 为每个数字返回超过 7 个十进制数字,则无论如何您都可以将该数据存储在您的字符串中,以防万一您想检测一些 flees or microbes in the future; 您可以使用他们的distance matrix 或geometry library 来计算距离,或者使用detecting points in certain areas 调用,就像这样简单:google.maps.geometry.poly.containsLocation(latLng, bermudaTrianglePolygon)) 有很多“服务器端”API 可供您使用(Python、Ruby on Rails、PHP、CodeIgniter、Laravel、Yii、Zend Framework 等)使用 Google Maps API。

这样您就不必担心索引数字以及与数据类型相关的所有其他问题,这些问题可能会破坏您的坐标。

【讨论】:

不好。 OP 说他将对 lat/lng 对进行计算 - 你的答案排除了【参考方案12】:

TL;DR

如果您不是在 NASA/军方工作,也不是制造飞机导航系统,请使用 FLOAT(8,5)。


要全面回答您的问题,您需要考虑几件事:

格式

度分秒:40° 26′ 46″ N 79° 58′ 56″ W 度十进制分: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”之类的坐标,但是您在导航到该点时是否关心过毫米?如果您不是在 NASA 工作,也不是在研究卫星、火箭或飞机的轨迹,那么几米的精度应该没问题。

常用的格式是点后 5 位数字,精度为 50 厘米。

示例:X,21.2780818和X,21.2780819之间有1cm的距离。因此,点后的 7 位数字为您提供 1/2 厘米的精度,点后的 5 位数字为您提供 1/2 米的精度(因为不同点之间的最小距离为 1m,因此舍入误差不能超过一半)。对于大多数民用目的来说,这应该足够了。

度十进制分钟格式(40° 26.767′ N 79° 58.933′ W)为您提供与点后 5 位数字完全相同的精度

节省空间的存储

如果您选择了十进制格式,那么您的坐标是一对(-32.60875、21.27812)。显然,2 x(符号 1 位,度数 2 位,指数 5 位)就足够了。

所以在这里我想支持来自 cmets 的 Alix Axel 说 Google 建议将其存储在 FLOAT(10,6) 中确实是额外的,因为您不需要 4 位数字作为 main部分(因为符号是分开的,纬度限制为 90,经度限制为 180)。您可以轻松地将 FLOAT(8,5) 用于 1/2m 精度或 FLOAT(9,6) 用于 50/2cm 精度。或者您甚至可以将 lat 和 long 存储在单独的类型中,因为 FLOAT(7,5) 足以存储 lat。请参阅 MySQL 浮点类型 reference。它们中的任何一个都会像普通的 FLOAT 一样,无论如何都等于 4 个字节。

现在空间通常不是问题,但如果您出于某种原因想要真正优化存储(免责声明:不要进行预优化),您可以压缩 lat(不超过 91 000 个值 + 符号)+ long(不超过 181 000 个值 + 符号)到​​ 21 位,明显小于 2xFLOAT(8 字节 == 64 位)

【讨论】:

不只是 NASA 需要高精度。土木工程师和建筑商也需要它,否则你会在停车场和建筑物中遇到大水坑,所有的大理石都滚到角落里。但测量员并不依赖标准的手机级 GPS。对于标准 GPS,FLOAT(IEEE488 32 位浮点格式)具有足够的精度。【参考方案13】:

根据您的应用程序,我建议使用 FLOAT(9,6)

空间键将为您提供更多功能,但在生产基准测试中,浮点数比空间键快得多。 (0,01 VS 0,001 在 AVG)

【讨论】:

你能在这里提供你的测试结果吗?【参考方案14】:

MySQL 对所有浮点数使用 double ... 所以使用双精度型。在大多数情况下,使用浮点数会导致不可预测的舍入值

【讨论】:

MySQL DOUBLE中执行操作。 MySQL 允许您将数据存储为 4 字节 FLOAT 或 8 字节 DOUBLE。因此,将表达式存储到 FLOAT 列时可能会丢失精度。【参考方案15】:

虽然它并非对所有操作都是最佳的,但如果您正在制作地图图块或使用只有一个投影的大量标记(点)(例如墨卡托,如谷歌地图和许多其他滑动地图框架所期望的),我发现我所说的“大坐标系”非常非常方便。基本上,您以某种方式放大存储 x 和 y 像素坐标——我使用缩放级别 23。这有几个好处:

您只需执行一次昂贵的 lat/lng 到墨卡托像素转换,而不是每次处理该点时 从给定缩放级别的记录中获取图块坐标需要右移一次。 从记录中获取像素坐标需要一次右移和一次按位与。 移位非常轻量级,可以在 SQL 中执行,这意味着您可以执行 DISTINCT 以每个像素位置仅返回一条记录,这将减少后端返回的记录数,这意味着更少在前端处理。

我在最近的一篇博文中谈到了这一切: http://blog.webfoot.com/2013/03/12/optimizing-map-tile-generation/

【讨论】:

【参考方案16】:

    纬度范围从 -90 到 +90(度),因此 DECIMAL(10, 8) 是可以的

    经度范围从 -180 到 +180(度),因此您需要 DECIMAL(11, 8)。

注意:第一个数字是存储的总位数,第二个是小数点后的数字。

简而言之:lat DECIMAL(10, 8) NOT NULL, lng DECIMAL(11, 8) NOT NULL

【讨论】:

【参考方案17】:

PostGIS 中的空间函数比 MySQL 空间函数中的函数更实用(即不受 BBOX 操作的限制)。看看吧:link text

【讨论】:

【参考方案18】:

我建议您对 SQL Server 使用 Float 数据类型。

【讨论】:

【参考方案19】:

存储 Lat Long 值的理想数据类型是小数(9,6)

这大约是 10 厘米的精度,同时仅使用 5 个字节的存储空间。

例如CAST(123.456789 作为十进制(9,6))

【讨论】:

【参考方案20】:

Lat Long 计算需要精度,因此请使用某种类型的小数类型并使精度至少比您要存储的数字高 2 以执行数学计算。我不知道我的 sql 数据类型,但在 SQL Server 中,人们经常使用浮点数或实数而不是十进制数并遇到麻烦,因为这些是估计数字而不是真实数字。所以只要确保你使用的数据类型是真正的十进制类型而不是浮点十进制类型就可以了。

【讨论】:

浮点型和小数型都有它们的位置。根据经验,浮点数表示物理变量,小数表示可数实体(主要是金钱)。我不明白为什么你更喜欢小数作为纬度/经度 我也认为浮点数适用于纬度/经度。至少在 SQL Server 上(4 字节,7 位)。 float估计不准确,lat long中的准确湖是致命的!它可以将您指向地球上一个完全不同的地方。 浮点数据类型的最大错误足够低,这应该不是问题。我的意思是,无论如何,您都必须注意两种实现的错误乘法/累积。 @HLGEM - 四舍五入到一些 小数 位也会使您在地球上的不同位置。问题是那个不同的地点是否如此接近以至于无关紧要。【参考方案21】:

@987654321@ 应该为您提供所需的所有精度,并且比将每个坐标存储为字符串等更适合比较函数。

如果您的 MySQL 版本早于 5.0.3,您可能需要注意某些 floating point comparison errors。

在 MySQL 5.0.3 之前,DECIMAL 列以精确的精度存储值,因为它们表示为字符串,但 DECIMAL 值的计算是使用浮点运算完成的。从 5.0.3 开始,MySQL 以 64 位十进制数字的精度执行 DECIMAL 运算,这应该可以解决涉及 DECIMAL 列时最常见的不准确问题

【讨论】:

您需要一个真正的纬度/经度坐标数据类型以便于计算。想象一下类似于“select * from stores where distance(stores.location, mylocation) 之前没听说过空间扩展,听上去挺方便的好吧,之前做过一个继承的应用,做了很多地理相关的计算,一定要看看。跨度> @ConroyP - 不。那句话指出DECIMAL(在 5.0.3 之前)由于使用浮动实现而存在某些错误。

以上是关于关于MYSQL 时间类型存储在数据库里是啥类型的主要内容,如果未能解决你的问题,请参考以下文章

存储纬度和经度的最佳 mysql 数据类型是啥?

“mysql”的存储类型“bit”是啥?

c语言里的LPARAM类型对应的c#里是啥类型呢? LPARAM到底是怎么样的一个类型啊?

“decimal”是啥类型的MySQL?

C#的EF中的字段类型布尔型,mysql数据库里是bit类型,提交识别不了该字段赋的true和false,为啥呢?

mediumint 在mysql 中是啥类型