MySQL_第12章_MySQL数据类型精讲

news2025/4/17 3:42:20

12_MySQL数据类型精讲

1. MySQL中的数据类型

类型
类型举例
整数类型
TINYINT SMALLINT MEDIUMINT INT( INTEGER) BIGINT
浮点类型
FLOAT DOUBLE
定点数类型
DECIMAL
位类型
BIT
日期时间类型
YEAR TIME DATE DATETIME TIMESTAMP
文本字符串类型
CHAR VARCHAR TINYTEXT TEXT MEDIUMTEXT LONGTEXT
枚举类型
ENUM
集合类型
SET
二进制字符串类
BINARY VARBINARY TINYBLOB BLOB MEDIUMBLOB LONGBLOB
JSON 类型
JSON 对象、 JSON 数组
空间数据类型
单值类型: GEOMETRY POINT LINESTRING POLYGON
集合类型: MULTIPOINT MULTILINESTRING MULTIPOLYGON
GEOMETRYCOLLECTION
常见数据类型的属性,如下:
MySQL 关键字
含义
NULL
数据列可包含 NULL
NOT NULL
数据列不允许包含 NULL
DEFAULT
默认值
PRIMARY KEY
主键
AUTO_INCREMENT
自动递增,适用于整数类型
UNSIGNED
无符号
CHARACTER SET name
指定一个字符集

2. 整数类型

2.1 类型介绍

整数类型一共有 5 种,包括 TINYINT SMALLINT MEDIUMINT INT (INTEGER)和 BIGINT
它们的区别如下表所示:
整数类型
字节
有符号数取值范围
无符号数取值范
TINYINT
1
-128~127
0~255
SMALLINT
2
-32768~32767
0~65535
MEDIUMINT
3
-8388608~8388607
0~16777215
INT INTEGER
4
-2147483648~2147483647
0~4294967295
BIGINT
8
-9223372036854775808~9223372036854775807
0~18446744073709551615

2.2 可选属性

整数类型的可选属性有三个:
2.2.1 M
M : 表示显示宽度, M 的取值范围是 (0, 255) 。例如, int(5) :当数据宽度小于 5 位的时候在数字前面需要用字符填满宽度。该项功能需要配合“ ZEROFILL 使用,表示用 “0” 填满宽度,否则指定显示宽度无效。
如果设置了显示宽度,那么插入的数据宽度超过显示宽度限制,会不会截断或插入失败?
答案:不会对插入的数据有任何影响,还是按照类型的实际宽度进行保存,即 显示宽度与类型可以存储的值范围无关 MySQL 8.0.17 开始,整数数据类型不推荐使用显示宽度属性。
整型数据类型可以在定义表结构时指定所需要的显示宽度,如果不指定,则系统为每一种类型指定默认的宽度值。
举例:
CREATE TABLE test_int1 ( x TINYINT , y SMALLINT , z MEDIUMINT , m INT , n BIGINT );
查看表结构 ( MySQL5.7 中显式如下, MySQL8 中不再显式范围)
mysql> desc test_int1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| x | tinyint ( 4 ) | YES | | NULL | |
| y | smallint ( 6 ) | YES | | NULL | |
| z | mediumint ( 9 ) | YES | | NULL | |
| m | int ( 11 ) | YES | | NULL | |
| n | bigint ( 20 ) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
5 rows in set ( 0.00 sec)
TINYINT 有符号数和无符号数的取值范围分别为 -128~127 0~255 ,由于负号占了一个数字位,因此TINYINT默认的显示宽度为 4 。同理,其他整数类型的默认显示宽度与其有符号数的最小值的宽度相同。
举例:
CREATE TABLE test_int2(
f1 INT ,
f2 INT ( 5 ),
f3 INT ( 5 ) ZEROFILL
)
DESC test_int2;
INSERT INTO test_int2(f1,f2,f3)
VALUES ( 1 , 123 , 123 );
INSERT INTO test_int2(f1,f2)
VALUES ( 123456 , 123456 );
INSERT INTO test_int2(f1,f2,f3)
VALUES ( 123456 , 123456 , 123456 );
mysql> SELECT * FROM test_int2;
+--------+--------+--------+
| f1 | f2 | f3 |
+--------+--------+--------+
| 1 | 123 | 00123 |
| 123456 | 123456 | NULL |
| 123456 | 123456 | 123456 |
+--------+--------+--------+
3 rows in set ( 0.00 sec)
2.2.2 UNSIGNED
UNSIGNED : 无符号类型(非负),所有的整数类型都有一个可选的属性 UNSIGNED (无符号属性),无符号整数类型的最小取值为0 。所以,如果需要在 MySQL 数据库中保存非负整数值时,可以将整数类型设置为无符号类型。
int 类型默认显示宽度为 int(11) ,无符号 int 类型默认显示宽度为 int(10)
CREATE TABLE test_int3(
f1 INT UNSIGNED
);
mysql> desc test_int3;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| f1 | int ( 10 ) unsigned | YES | | NULL | |
+-------+------------------+------+-----+---------+-------+
1 row in set ( 0.00 sec)
2.2.3 ZEROFILL
ZEROFILL : 0 填充 , (如果某列是 ZEROFILL ,那么 MySQL 会自动为当前列添加 UNSIGNED 属性),如果指定了ZEROFILL 只是表示不够 M 位时,用 0 在左边填充,如果超过 M 位,只要不超过数据存储范围即可。
原来,在 int(M) 中, M 的值跟 int(M) 所占多少存储空间并无任何关系。 int(3) int(4) int(8) 在磁盘上都是占用 4 bytes 的存储空间。也就是说, int(M) ,必须和 UNSIGNED ZEROFILL 一起使用才有意义。 如果整数值超过M 位,就按照实际位数存储。只是无须再用字符 0 进行填充。

2.3 适用场景

TINYINT :一般用于枚举数据,比如系统设定取值范围很小且固定的场景。
SMALLINT :可以用于较小范围的统计数据,比如统计工厂的固定资产库存数量等。
MEDIUMINT :用于较大整数的计算,比如车站每日的客流量等。
INT INTEGER :取值范围足够大,一般情况下不用考虑超限问题,用得最多。比如商品编号。
BIGINT :只有当你处理特别巨大的整数时才会用到。比如双十一的交易量、大型门户网站点击量、证券公司衍生产品持仓等。

2.4 如何选择?

在评估用哪种整数类型的时候,你需要考虑 存储空间 可靠性 的平衡问题:一方 面,用占用字节数少的整数类型可以节省存储空间;另一方面,要是为了节省存储空间, 使用的整数类型取值范围太小,一旦遇到超出取值范围的情况,就可能引起 系统错误 ,影响可靠性。
举个例子,商品编号采用的数据类型是 INT 。原因就在于,客户门店中流通的商品种类较多,而且,每天都有旧商品下架,新商品上架,这样不断迭代,日积月累。
如果使用 SMALLINT 类型,虽然占用字节数比 INT 类型的整数少,但是却不能保证数据不会超出范围65535。相反,使用 INT ,就能确保有足够大的取值范围,不用担心数据超出范围影响可靠性的问题。
你要注意的是,在实际工作中, 系统故障产生的成本远远超过增加几个字段存储空间所产生的成本 。因此,我建议你首先确保数据不会超过取值范围,在这个前提之下,再去考虑如何节省存储空间。

3. 浮点类型

3.1 类型介绍

浮点数和定点数类型的特点是可以 处理小数 ,你可以把整数看成小数的一个特例。因此,浮点数和定点数的使用场景,比整数大多了。 MySQL 支持的浮点数类型,分别是 FLOAT DOUBLE REAL
  • FLOAT 表示单精度浮点数;
  • DOUBLE 表示双精度浮点数;

 

  • REAL默认就是 DOUBLE。如果你把 SQL 模式设定为启用REAL_AS_FLOAT ,那 么,MySQL 就认为 REAL FLOAT。如果要启用“REAL_AS_FLOAT”,可以通过以下 SQL 语句实现:

SET sql_mode = “REAL_AS_FLOAT”;

问题 1 FLOAT DOUBLE 这两种数据类型的区别是啥呢?
SET sql_mode = “REAL_AS_FLOAT”; FLOAT 占用字节数少,取值范围小; DOUBLE 占用字节数多,取值范围也大。
问题 2 为什么浮点数类型的无符号数取值范围,只相当于有符号数取值范围的一半,也就是只相当于有符号数取值范围大于等于零的部分呢?
MySQL 存储浮点数的格式为: 符号 (S) 尾数 (M) 阶码 (E) 。因此,无论有没有符号, MySQL 的浮点数都会存储表示符号的部分。因此, 所谓的无符号数取值范围,其实就是有符号数取值范围大于等于零的部分。

3.2 数据精度说明

对于浮点类型,在MySQL 中单精度值使用 4 个字节,双精度值使用 8 个字节。
  • MySQL允许使用 非标准语法 (其他数据库未必支持,因此如果涉及到数据迁移,则最好不要这么用): FLOAT(M,D) DOUBLE(M,D) 。这里,M称为 精度 D称为 标度 (M,D)M=整数位+小数位,D=小数位。 D<=M<=2550<=D<=30例如,定义为FLOAT(5,2)的一个列可以显示为-999.99-999.99。如果超过这个范围会报错。
  • FLOATDOUBLE类型在不指定(M,D)时,默认会按照实际的精度(由实际的硬件和操作系统决定)来显示。
  • 说明:浮点类型,也可以加 UNSIGNED ,但是不会改变数据范围,例如:FLOAT(3,2) UNSIGNED仍然只能表示0-9.99的范围。
  • 不管是否显式设置了精度(M,D),这里MySQL的处理方案如下:
    • 如果存储时,整数部分超出了范围,MySQL就会报错,不允许存这样的值
    • 如果存储时,小数点部分若超出范围,就分以下情况:
      • 若四舍五入后,整数部分没有超出范围,则只警告,但能成功操作并四舍五入删除多余的小数位后保存。例如在FLOAT(5,2)列内插入999.009,近似结果是999.01
      • 若四舍五入后,整数部分超出范围,则MySQL报错,并拒绝处理。如FLOAT(5,2)列内插入999.995-999.995都会报错。
  • MySQL 8.0.17开始,FLOAT(M,D) DOUBLE(M,D)用法在官方文档中已经明确不推荐使用,将来可能被移除。另外,关于浮点型FLOATDOUBLEUNSIGNED也不推荐使用了,将来也可能被移除。
  • 举例
CREATE TABLE test_double1(
f1 FLOAT ,
f2 FLOAT ( 5 , 2 ),
f3 DOUBLE ,
f4 DOUBLE ( 5 , 2 )
);
DESC test_double1;
INSERT INTO test_double1
VALUES ( 123.456 , 123.456 , 123.4567 , 123.45 );
#Out of range value for column 'f2' at row 1
INSERT INTO test_double1
VALUES ( 123.456 , 1234.456 , 123.4567 , 123.45 );
SELECT * FROM test_double1;

3.3 精度误差说明

浮点数类型有个缺陷,就是不精准。下面我来重点解释一下为什么 MySQL 的浮点数不够精准。比如,我们设计一个表,有f1 这个字段,插入值分别为 0.47,0.44,0.19 ,我们期待的运行结果是: 0.47 + 0.44 + 0.19 = 1.1。而使用 sum 之后查询:
CREATE TABLE test_double2(
f1 DOUBLE
);
INSERT INTO test_double2
VALUES ( 0.47 ),( 0.44 ),( 0.19 );

 mysql> SELECT SUM(f1)

-> FROM test_double2;
+--------------------+
| SUM (f1) |
+--------------------+
| 1.0999999999999999 |
+--------------------+
1 row in set ( 0.00 sec)
mysql> SELECT SUM (f1) = 1.1 , 1.1 = 1.1
-> FROM test_double2;
+---------------+-----------+
| SUM (f1) = 1.1 | 1.1 = 1.1 |
+---------------+-----------+
| 0 | 1 |
+---------------+-----------+
1 row in set ( 0.00 sec)
查询结果是 1.0999999999999999 。看到了吗?虽然误差很小,但确实有误差。 你也可以尝试把数据类型改成 FLOAT ,然后运行求和查询,得到的是, 1.0999999940395355 。显然,误差更大了。
那么,为什么会存在这样的误差呢?问题还是出在 MySQL 对浮点类型数据的存储方式上。
MySQL 4 个字节存储 FLOAT 类型数据,用 8 个字节来存储 DOUBLE 类型数据。无论哪个,都是采用二进制的方式来进行存储的。比如 9.625 ,用二进制来表达,就是 1001.101 ,或者表达成 1.001101×2^3 。如果尾数不是 0 5 (比如 9.624 ),你就无法用一个二进制数来精确表达。进而,就只好在取值允许的范围内进行四舍五入。
在编程中,如果用到浮点数,要特别注意误差问题, 因为浮点数是不准确的,所以我们要避免使用 “=” 判断两个数是否相等。 同时,在一些对精确度要求较高的项目中,千万不要使用浮点数,不然会导致结果错误,甚至是造成不可挽回的损失。那么,MySQL 有没有精准的数据类型呢?当然有,这就是定点数类型: DECIMAL

4. 定点数类型

4.1 类型介绍

  • MySQL中的定点数类型只有 DECIMAL 一种类型。
数据类型
字节数
含义
DECIMAL(M,D),DEC,NUMERIC
M+2 字节
有效范围由 M D 决定
使用 DECIMAL(M,D) 的方式表示高精度小数。其中, M 被称为精度, D 被称为标度。 0<=M<=65
0<=D<=30 D<M 。例如,定义 DECIMAL (5,2)的类型,表示该列取值范围是 -999.99~999.99
  • DECIMAL(M,D)的最大取值范围与DOUBLE类型一样,但是有效的数据范围是由MD决定的。 DECIMAL 的存储空间并不是固定的,由精度值M决定,总共占用的存储空间为M+2个字节。也就是说,在一些对精度要求不高的场景下,比起占用同样字节长度的定点数,浮点数表达的数值范围可以更大一些。
  • 定点数在MySQL内部是以 字符串 的形式进行存储,这就决定了它一定是精准的。
  • DECIMAL类型不指定精度和标度时,其默认为DECIMAL(10,0)。当数据的精度超出了定点数类型的精度范围时,则MySQL同样会进行四舍五入处理。
  • 浮点数 vs 定点数
    • 浮点数相对于定点数的优点是在长度一定的情况下,浮点类型取值范围大,但是不精准,适用于需要取值范围大,又可以容忍微小误差的科学计算场景(比如计算化学、分子建模、流体动力学等)
    • 定点数类型取值范围相对小,但是精准,没有误差,适合于对精度要求极高的场景 (比如涉及金额计算的场景)
  • 举例

CREATE TABLE test_decimal1(
f1 DECIMAL ,
f2 DECIMAL ( 5 , 2 )
);
DESC test_decimal1;
INSERT INTO test_decimal1(f1,f2)
VALUES ( 123.123 , 123.456 );
#Out of range value for column 'f2' at row 1
INSERT INTO test_decimal1(f2)
VALUES ( 1234.34 );
mysql> SELECT * FROM test_decimal1;
+------+--------+
| f1 | f2 |
+------+--------+
| 123 | 123.46 |
+------+--------+
1 row in set ( 0.00 sec)
  • 举例
我们运行下面的语句,把 test_double2 表中字段 “f1” 的数据类型修改为 DECIMAL(5,2)
ALTER TABLE test_double2
MODIFY f1 DECIMAL ( 5 , 2 );
然后,我们再一次运行求和语句:
mysql> SELECT SUM (f1)
-> FROM test_double2;
+---------+
| SUM (f1) |
+---------+
| 1.10 |
+---------+
1 row in set ( 0.00 sec)
mysql> SELECT SUM (f1) = 1.1
-> FROM test_double2;
+---------------+
| SUM (f1) = 1.1 |
+---------------+
| 1 |
+---------------+
1 row in set ( 0.00 sec)

4.2 开发中经验

由于 DECIMAL 数据类型的精准性,在我们的项目中,除了极少数(比如商品编号)用到整数类型外,其他的数值都用的是 DECIMAL ,原因就是这个项目所处的零售行业,要求精准,一分钱也不能差。 ” —— 来自某项目经理

5. 位类型:BIT

BIT 类型中存储的是二进制值,类似 010110
二进制字符串类型
长度
长度范围
占用空间
BIT(M)
M
1 <= M <= 64
约为 (M + 7)/8 个字节
BIT 类型,如果没有指定 (M) ,默认是 1 位。这个 1 位,表示只能存 1 位的二进制值。这里 (M) 是表示二进制的位数,位数最小值为1 ,最大值为 64
CREATE TABLE test_bit1(
f1 BIT ,
f2 BIT ( 5 ),
f3 BIT ( 64 )
);
INSERT INTO test_bit1(f1)
VALUES ( 1 );
#Data too long for column 'f1' at row 1
INSERT INTO test_bit1(f1)
VALUES ( 2 );
INSERT INTO test_bit1(f2)
VALUES ( 23 );
注意:在向BIT 类型的字段中插入数据时,一定要确保插入的数据在 BIT 类型支持的范围内。
使用 SELECT 命令查询位字段时,可以用 BIN() HEX() 函数进行读取。
mysql> SELECT * FROM test_bit1;
+------------+------------+------------+
| f1 | f2 | f3 |
+------------+------------+------------+
| 0x01 | NULL | NULL |
| NULL | 0x17 | NULL |
+------------+------------+------------+
2 rows in set ( 0.00 sec)
mysql> SELECT BIN(f2),HEX(f2)
-> FROM test_bit1;
+---------+---------+
| BIN(f2) | HEX(f2) |
+---------+---------+
| NULL | NULL |
| 10111 | 17 |
+---------+---------+
2 rows in set ( 0.00 sec)
mysql> SELECT f2 + 0
-> FROM test_bit1;
+--------+
| f2 + 0 |
+--------+
| NULL |
| 23 |
+--------+
2 rows in set ( 0.00 sec)
可以看到,使用 b+0 查询数据时,可以直接查询出存储的十进制数据的值。

6. 日期与时间类型

日期与时间是重要的信息,在我们的系统中,几乎所有的数据表都用得到。原因是客户需要知道数据的时间标签,从而进行数据查询、统计和处理。
MySQL 有多种表示日期和时间的数据类型,不同的版本可能有所差异, MySQL8.0 版本支持的日期和时间类型主要有:YEAR 类型、 TIME 类型、 DATE 类型、 DATETIME 类型和 TIMESTAMP 类型。  
  • YEAR 类型通常用来表示年
  • DATE 类型通常用来表示年、月、日
  • TIME 类型通常用来表示时、分、秒
  • DATETIME 类型通常用来表示年、月、日、时、分、秒
  • TIMESTAMP 类型通常用来表示带时区的年、月、日、时、分、秒
类型
名称
日期格式
最小值
最大值
YEAR
1
YYYY YY
1901
2155
TIME
时间
3
HH:MM:SS
-838:59:59
838:59:59
DATE
日期
3
YYYY-MM-DD
1000-01-01
9999-12-03
DATETIME
日期
时间
8
YYYY-MM-DD
HH:MM:SS
1000-01-01
00:00:00
9999-12-31
23:59:59
TIMESTAMP
日期
时间
4
YYYY-MM-DD
HH:MM:SS
1970-01-01
00:00:00 UTC
2038-01-19
03:14:07UTC
可以看到,不同数据类型表示的时间内容不同、取值范围不同,而且占用的字节数也不一样,你要根据实际需要灵活选取。
为什么时间类型 TIME 的取值范围不是 -23:59:59 23:59:59 呢?原因是 MySQL 设计的 TIME 类型,不光表示一天之内的时间,而且可以用来表示一个时间间隔,这个时间间隔可以超过 24 小时。

6.1 YEAR类型

YEAR 类型用来表示年份,在所有的日期时间类型中所占用的存储空间最小,只需要 1 个字节 的存储空间。
MySQL 中, YEAR 有以下几种存储格式:
  • 4位字符串或数字格式表示YEAR类型,其格式为YYYY,最小值为1901,最大值为2155
  • 2位字符串格式表示YEAR类型,最小值为00,最大值为99
    • 当取值为0169时,表示20012069
    • 当取值为7099时,表示19701999
    • 当取值整数的000添加的话,那么是0000年;
    • 当取值是日期/字符串的'0'添加的话,是2000年。
MySQL5.5.27 开始, 2 位格式的 YEAR 已经不推荐使用 YEAR 默认格式就是 “YYYY” ,没必要写成 YEAR(4)
MySQL 8.0.19 开始,不推荐使用指定显示宽度的 YEAR(4) 数据类型。
CREATE TABLE test_year(
f1 YEAR ,
f2 YEAR ( 4 )
);
mysql> DESC test_year;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| f1 | year ( 4 ) | YES | | NULL | |
| f2 | year ( 4 ) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
2 rows in set ( 0.00 sec)
INSERT INTO test_year
VALUES ( '2020' , '2021' );
mysql> SELECT * FROM test_year;
+------+------+
| f1 | f2 |
+------+------+
| 2020 | 2021 |
+------+------+
1 rows in set ( 0.00 sec)  
INSERT INTO test_year
VALUES ( '45' , '71' );
INSERT INTO test_year
VALUES ( 0 , '0' );
mysql> SELECT * FROM test_year;
+------+------+
| f1 | f2 |
+------+------+
| 2020 | 2021 |
| 2045 | 1971 |
| 0000 | 2000 |
+------+------+
3 rows in set ( 0.00 sec)  

6.2 DATE类型

DATE 类型表示日期,没有时间部分,格式为 YYYY - MM - DD ,其中, YYYY 表示年份, MM 表示月份, DD 表示日期。需要 3 个字节 的存储空间。在向 DATE 类型的字段插入数据时,同样需要满足一定的格式条件。
  • YYYY-MM-DD 格式或者 YYYYMMDD 格式表示的字符串日期,其最小取值为1000-01-01,最大取值为9999-12-03YYYYMMDD格式会被转化为YYYY-MM-DD格式。
  • YY-MM-DD 格式或者 YYMMDD 格式表示的字符串日期,此格式中,年份为两位数值或字符串满足YEAR类型的格式条件为:当年份取值为0069时,会被转化为20002069;当年份取值为7099时,会被转化为19701999
  • 使用 CURRENT_DATE() 或者 NOW() 函数,会插入当前系统的日期。
举例:
创建数据表,表中只包含一个 DATE 类型的字段 f1
CREATE TABLE test_date1(
f1 DATE
);
Query OK, 0 rows affected ( 0.13 sec)
插入数据:
INSERT INTO test_date1
VALUES ( '2020-10-01' ), ( '20201001' ),( 20201001 );
INSERT INTO test_date1
VALUES ( '00-01-01' ), ( '000101' ), ( '69-10-01' ), ( '691001' ), ( '70-01-01' ), ( '700101' ),
( '99-01-01' ), ( '990101' );
INSERT INTO test_date1
VALUES ( 000301 ), ( 690301 ), ( 700301 ), ( 990301 );
INSERT INTO test_date1
VALUES ( CURRENT_DATE ()), (NOW());
SELECT *
FROM test_date1;

6.3 TIME类型

TIME 类型用来表示时间,不包含日期部分。在 MySQL 中,需要 3 个字节 的存储空间来存储 TIME 类型的数据,可以使用“HH:MM:SS” 格式来表示 TIME 类型,其中, HH 表示小时, MM 表示分钟, SS 表示秒。
在MySQL 中,向 TIME 类型的字段插入数据时,也可以使用几种不同的格式。
(1)可以使用带有冒号的字符串,比如' D HH:MM:SS' ' HH:MM:SS ' ' HH:MM ' ' D HH:MM ' ' D HH ' ' SS ' 格式,都能被正确地插入TIME 类型的字段中。其中 D 表示天,其最小值为 0 ,最大值为 34 。如果使用带有 D 格式的字符串插入TIME 类型的字段时, D 会被转化为小时,计算格式为 D*24+HH 。当使用带有冒号并且不带 D 的字符串表示时间时,表示当天的时间,比如12:10 表示 12:10:00 ,而不是 00:12:10
(2)可以使用不带有冒号的字符串或者数字,格式为' HHMMSS ' 或者 HHMMSS 。如果插入一个不合法的字符串或者数字, MySQL 在存储数据时,会将其自动转化为00:00:00 进行存储。比如 1210 MySQL 会将最右边的两位解析成秒,表示00:12:10,而不是 12:10:00
(3)使用 CURRENT_TIME() 或者 NOW() ,会插入当前系统的时间。
举例:
创建数据表,表中包含一个 TIME 类型的字段 f1
CREATE TABLE test_time1(
f1 TIME
);
Query OK, 0 rows affected ( 0.02 sec)
INSERT INTO test_time1
VALUES ( '2 12:30:29' ), ( '12:35:29' ), ( '12:40' ), ( '2 12:40' ),( '1 05' ), ( '45' );
INSERT INTO test_time1
VALUES ( '123520' ), ( 124011 ),( 1210 );
INSERT INTO test_time1
VALUES (NOW()), ( CURRENT_TIME ());
SELECT * FROM test_time1;

6.4 DATETIME类型

DATETIME 类型在所有的日期时间类型中占用的存储空间最大,总共需要 8 个字节的存储空间。在格式上为DATE 类型和 TIME 类型的组合,可以表示为 YYYY - MM - DD HH:MM:SS ,其中 YYYY 表示年份, MM 表示月份,DD 表示日期, HH 表示小时, MM 表示分钟, SS 表示秒。
在向 DATETIME 类型的字段插入数据时,同样需要满足一定的格式条件。
  • YYYY-MM-DD HH:MM:SS 格式或者 YYYYMMDDHHMMSS 格式的字符串插入DATETIME类型的字段时,最小值为1000-01-01 00:00:00,最大值为9999-12-03 23:59:59
    • YYYYMMDDHHMMSS格式的数字插入DATETIME类型的字段时,会被转化为YYYY-MM-DD HH:MM:SS格式。
  • YY-MM-DD HH:MM:SS 格式或者 YYMMDDHHMMSS 格式的字符串插入DATETIME类型的字段时,两位数的年份规则符合YEAR类型的规则,0069表示200020697099表示19701999
  • 使用函数 CURRENT_TIMESTAMP() NOW() ,可以向DATETIME类型的字段插入系统的当前日期和时间。
举例:
创建数据表,表中包含一个 DATETIME 类型的字段 dt
CREATE TABLE test_datetime1(
dt DATETIME
);
Query OK, 0 rows affected ( 0.02 sec)
插入数据:
INSERT INTO test_datetime1
VALUES ( '2021-01-01 06:50:30' ), ( '20210101065030' );
INSERT INTO test_datetime1
VALUES ( '99-01-01 00:00:00' ), ( '990101000000' ), ( '20-01-01 00:00:00' ),
( '200101000000' );
INSERT INTO test_datetime1
VALUES ( 20200101000000 ), ( 200101000000 ), ( 19990101000000 ), ( 990101000000 );
INSERT INTO test_datetime1
VALUES ( CURRENT_TIMESTAMP ()), (NOW());

6.5 TIMESTAMP类型

TIMESTAMP 类型也可以表示日期时间,其显示格式与 DATETIME 类型相同,都是 YYYY - MM - DD
HH:MM:SS ,需要 4 个字节的存储空间。但是 TIMESTAMP 存储的时间范围比 DATETIME 要小很多,只能存储 “1970-01-01 00:00:01 UTC”到 “2038-01-19 03:14:07 UTC” 之间的时间。其中, UTC 表示世界统一时间,也叫作世界标准时间。
  • 存储数据的时候需要对当前时间所在的时区进行转换,查询数据的时候再将时间转换回当前的时区。因此,使用TIMESTAMP存储的同一个时间值,在不同的时区查询时会显示不同的时间。
TIMESTAMP 类型的字段插入数据时,当插入的数据格式满足 YY-MM-DD HH:MM:SS YYMMDDHHMMSS时,两位数值的年份同样符合YEAR 类型的规则条件,只不过表示的时间范围要小很多。
如果向 TIMESTAMP 类型的字段插入的时间超出了 TIMESTAMP 类型的范围,则 MySQL 会抛出错误信息。
举例:
创建数据表,表中包含一个 TIMESTAMP 类型的字段 ts
CREATE TABLE test_timestamp1(
ts TIMESTAMP
);
插入数据:
INSERT INTO test_timestamp1
VALUES ( '1999-01-01 03:04:50' ), ( '19990101030405' ), ( '99-01-01 03:04:05' ),
( '990101030405' );
INSERT INTO test_timestamp1
VALUES ( '2020@01@01@00@00@00' ), ( '20@01@01@00@00@00' );
INSERT INTO test_timestamp1
VALUES ( CURRENT_TIMESTAMP ()), (NOW());
#Incorrect datetime value
INSERT INTO test_timestamp1
VALUES ( '2038-01-20 03:14:07' );
TIMESTAMP DATETIME 的区别:
  • TIMESTAMP存储空间比较小,表示的日期时间范围也比较小
  • 底层存储方式不同,TIMESTAMP底层存储的是毫秒值,距离1970-1-1 0:0:0 0毫秒的毫秒值。
  • 两个日期比较大小或日期计算时,TIMESTAMP更方便、更快。
  • TIMESTAMP和时区有关。TIMESTAMP会根据用户的时区不同,显示不同的结果。而DATETIME则只能反映出插入时当地的时区,其他时区的人查看数据必然会有误差的。
CREATE TABLE temp_time(
d1 DATETIME ,
d2 TIMESTAMP
);
INSERT INTO temp_time VALUES ( '2021-9-2 14:45:52' , '2021-9-2 14:45:52' );
INSERT INTO temp_time VALUES (NOW(),NOW());
mysql> SELECT * FROM temp_time;
+---------------------+---------------------+
| d1 | d2 |
+---------------------+---------------------+
| 2021 - 09 - 02 14 :45:52 | 2021 - 09 - 02 14 :45:52 |
| 2021 - 11 - 03 17 :38:17 | 2021 - 11 - 03 17 :38:17 |
+---------------------+---------------------+
2 rows in set ( 0.00 sec)
# 修改当前的时区
SET time_zone = '+9:00' ;
mysql> SELECT * FROM temp_time;
+---------------------+---------------------+
| d1 | d2 |
+---------------------+---------------------+
| 2021 - 09 - 02 14 :45:52 | 2021 - 09 - 02 15 :45:52 |
| 2021 - 11 - 03 17 :38:17 | 2021 - 11 - 03 18 :38:17 |
+---------------------+---------------------+
2 rows in set ( 0.00 sec)

6.6 开发中经验

用得最多的日期时间类型,就是 DATETIME 。虽然 MySQL 也支持 YEAR (年)、 TIME (时间)、DATE(日期),以及 TIMESTAMP 类型,但是在实际项目中,尽量用 DATETIME 类型。因为这个数据类型包括了完整的日期和时间信息,取值范围也最大,使用起来比较方便。毕竟,如果日期时间信息分散在好几个字段,很不容易记,而且查询的时候,SQL 语句也会更加复杂。
此外,一般存注册时间、商品发布时间等,不建议使用 DATETIME 存储,而是使用 时间戳 ,因为
DATETIME 虽然直观,但不便于计算。

7. 文本字符串类型

在实际的项目中,我们还经常遇到一种数据,就是字符串数据。
MySQL 中,文本字符串总体上分为 CHAR VARCHAR TINYTEXT TEXT MEDIUMTEXT LONGTEXT ENUM SET 等类型。

 

7.1 CHARVARCHAR类型

CHAR VARCHAR 类型都可以存储比较短的字符串。
字符串 ( 文本 ) 类型
特点
长度
长度范围
占用的存储空间
CHAR(M)
固定长度
M
0 <= M <= 255
M 个字节
VARCHAR(M)
可变长度
M
0 <= M <= 65535
( 实际长度 + 1) 个字节

CHAR类型:

  • CHAR(M) 类型一般需要预先定义字符串长度。如果不指定(M),则表示长度默认是1个字符。
  • 如果保存时,数据的实际长度比CHAR类型声明的长度小,则会在 右侧填充 空格以达到指定的长度。当MySQL检索CHAR类型的数据时,CHAR类型的字段会去除尾部的空格。
  • 定义CHAR类型字段时,声明的字段长度即为CHAR类型字段所占的存储空间的字节数。
CREATE TABLE test_char1(
c1 CHAR ,
c2 CHAR ( 5 )
);
DESC test_char1;
INSERT INTO test_char1
VALUES ( 'a' , 'Tom' );
SELECT c1,CONCAT(c2, '***' ) FROM test_char1;
INSERT INTO test_char1(c2)
VALUES ( 'a ' );
SELECT CHAR_LENGTH(c2)
FROM test_char1;
VARCHAR 类型:
  • VARCHAR(M) 定义时, 必须指定 长度M,否则报错。
  • MySQL4.0版本以下,varchar(20):指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3节) ;MySQL5.0版本以上,varchar(20):指的是20字符。
  • 检索VARCHAR类型的字段数据时,会保留数据尾部的空格。VARCHAR类型的字段所占用的存储空间为字符串实际长度加1个字节。

CREATE TABLE test_varchar1(
NAME VARCHAR # 错误
);
#Column length too big for column 'NAME' (max = 21845);
CREATE TABLE test_varchar2(
NAME VARCHAR ( 65535 ) # 错误
);
CREATE TABLE test_varchar3(
NAME VARCHAR ( 5 )
);
INSERT INTO test_varchar3
VALUES ( ' 尚硅谷 ' ),( ' 尚硅谷教育 ' );
#Data too long for column 'NAME' at row 1
INSERT INTO test_varchar3
VALUES ( ' 尚硅谷 IT 教育 ' );
哪些情况使用 CHAR VARCHAR 更好
类型
特点
空间上
时间上
适用场景
CHAR(M)
固定长度
浪费存储空间
效率高
存储不大,速度要求高
VARCHAR(M)
可变长度
节省存储空间
效率低
CHAR 的情况

情况1:存储很短的信息。比如门牌号码101201……这样很短的信息应该用char,因为varchar还要占个byte用于存储信息长度,本来打算节约存储的,结果得不偿失。

情况 2 :固定长度的。比如使用 uuid 作为主键,那用 char 应该更合适。因为他固定长度, varchar 动态根据长度的特性就消失了,而且还要占个长度信息。
情况 3 :十分频繁改变的 column 。因为 varchar 每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而这些对于char 来说是不需要的。
情况 4 :具体存储引擎中的情况:
  • MyISAM 数据存储引擎和数据列:MyISAM数据表,最好使用固定长度(CHAR)的数据列代替可变长(VARCHAR)的数据列。这样使得整个表静态化,从而使 数据检索更快 ,用空间换时间。
  • MEMORY 存储引擎和数据列:MEMORY数据表目前都使用固定长度的数据行存储,因此无论使用CHARVARCHAR列都没有关系,两者都是作为CHAR类型处理的。
  • InnoDB 存储引擎,建议使用VARCHAR类型。因为对于InnoDB数据表,内部的行存储格式并没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),而且主要影响性能的因素是数据行使用的存储总量,由于char平均占用的空间多于varchar,所以除了简短并且固定长度的,其他考虑varchar。这样节省空间,对磁盘I/O和数据存储总量比较好。

7.2 TEXT类型

MySQL 中, TEXT 用来保存文本类型的字符串,总共包含 4 种类型,分别为 TINYTEXT TEXT
MEDIUMTEXT LONGTEXT 类型。
在向 TEXT 类型的字段保存和查询数据时,系统自动按照实际长度存储,不需要预先定义长度。这一点和VARCHAR类型相同。
每种 TEXT 类型保存的数据长度和所占用的存储空间不同,如下:
文本字符串类
特点
长度范围
占用的存储空
TINYTEXT
小文本、可变长度
L
0 <= L <= 255
L + 2 个字节
TEXT
文本、可变长度
L
0 <= L <= 65535
L + 2 个字节
MEDIUMTEXT
中等文本、可变长度
L
0 <= L <= 16777215
L + 3 个字节
LONGTEXT
大文本、可变长度
L
0 <= L<= 4294967295 (相当于
4GB
L + 4 个字节

由于实际存储的长度不确定, MySQL 不允许 TEXT 类型的字段做主键 。遇到这种情况,你只能采用CHAR(M),或者 VARCHAR(M)
举例:
创建数据表:
CREATE TABLE test_text(
tx TEXT
);
INSERT INTO test_text
VALUES ( 'atguigu ' );
SELECT CHAR_LENGTH(tx)
FROM test_text;
说明在保存和查询数据时,并没有删除 TEXT 类型的数据尾部的空格。
开发中经验:
TEXT 文本类型,可以存比较大的文本段,搜索速度稍慢,因此如果不是特别大的内容,建议使用 CHAR ,VARCHAR来代替。还有 TEXT 类型不用加默认值,加了也没用。而且 text blob 类型的数据删除后容易导致“空洞 ,使得文件碎片比较多,所以频繁使用的表不建议包含 TEXT 类型字段,建议单独分出去,单独用一个表。

8. ENUM类型

ENUM 类型也叫作枚举类型, ENUM 类型的取值范围需要在定义字段时进行指定。设置字段值时, ENUM类型只允许从成员中选取单个值,不能一次选取多个值。
其所需要的存储空间由定义 ENUM 类型时指定的成员个数决定。
文本字符串类型
长度
长度范围
占用的存储空间
ENUM
L
1 <= L <= 65535
1 2 个字节
  • ENUM类型包含1255个成员时,需要1个字节的存储空间;
  • ENUM类型包含25665535个成员时,需要2个字节的存储空间。
  • ENUM类型的成员个数的上限为65535个。
举例:
创建表如下:
CREATE TABLE test_enum(
season ENUM ( ' ' , ' ' , ' ' , ' ' , 'unknow' )
);
添加数据:
INSERT INTO test_enum
VALUES ( ' ' ),( ' ' );
# 忽略大小写
INSERT INTO test_enum
VALUES ( 'UNKNOW' );
# 允许按照角标的方式获取指定索引位置的枚举值
INSERT INTO test_enum
VALUES ( '1' ),( 3 );
# Data truncated for column 'season' at row 1
INSERT INTO test_enum
VALUES ( 'ab' );
# ENUM 类型的字段没有声明为 NOT NULL 时,插入 NULL 也是有效的
INSERT INTO test_enum
VALUES ( NULL );

9. SET类型

SET表示一个字符串对象,可以包含 0 个或多个成员,但成员个数的上限为 64 。设置字段值时,可以取取值范围内的 0 个或多个值。
SET 类型包含的成员个数不同时,其所占用的存储空间也是不同的,具体如下:
成员个数范围( L 表示实际成员个数)
占用的存储空间
1 <= L <= 8
1 个字节
9 <= L <= 16
2 个字节
17 <= L <= 24
3 个字节
25 <= L <= 32
4 个字节
33 <= L <= 64
8 个字节

SET类型在存储数据时成员个数越多,其占用的存储空间越大。注意:SET类型在选取成员时,可以一次选择多个成员,这一点与ENUM类型不同。

举例:
创建表:
CREATE TABLE test_set(
s SET ( 'A' , 'B' , 'C' )
);
向表中插入数据:
INSERT INTO test_set (s) VALUES ( 'A' ), ( 'A,B' );
# 插入重复的 SET 类型成员时, MySQL 会自动删除重复的成员
INSERT INTO test_set (s) VALUES ( 'A,B,C,A' );
# SET 类型的字段插入 SET 成员中不存在的值时, MySQL 会抛出错误。
INSERT INTO test_set (s) VALUES ( 'A,B,C,D' );
SELECT *
FROM test_set;
举例:
CREATE TABLE temp_mul(
gender ENUM ( ' ' , ' ' ),
hobby SET ( ' 吃饭 ' , ' 睡觉 ' , ' 打豆豆 ' , ' 写代码 ' )
);
INSERT INTO temp_mul VALUES ( ' ' , ' 睡觉 , 打豆豆 ' ); # 成功
# Data truncated for column 'gender' at row 1
INSERT INTO temp_mul VALUES ( ' , ' , ' 睡觉 , 写代码 ' ); # 失败
# Data truncated for column 'gender' at row 1
INSERT INTO temp_mul VALUES ( ' ' , ' 睡觉 , 写代码 ' ); # 失败
INSERT INTO temp_mul VALUES ( ' ' , ' 睡觉 , 写代码 , 吃饭 ' ); # 成功

10. 二进制字符串类型

MySQL 中的二进制字符串类型主要存储一些二进制数据,比如可以存储图片、音频和视频等二进制数据。
MySQL 中支持的二进制字符串类型主要包括 BINARY VARBINARY TINYBLOB BLOB MEDIUMBLOB 和LONGBLOB类型。
BINARY VARBINARY 类型
BINARY VARBINARY 类似于 CHAR VARCHAR ,只是它们存储的是二进制字符串。
BINARY (M) 为固定长度的二进制字符串, M 表示最多能存储的字节数,取值范围是 0~255 个字符。如果未指定(M) ,表示只能存储 1 个字节 。例如 BINARY (8) ,表示最多能存储 8 个字节,如果字段值不足 (M) 个字节,将在右边填充'\0' 以补齐指定长度。
VARBINARY (M) 为可变长度的二进制字符串, M 表示最多能存储的字节数,总字节数不能超过行的字节长度限制65535 ,另外还要考虑额外字节开销, VARBINARY 类型的数据除了存储数据本身外,还需要 1 2 个字节来存储数据的字节数。VARBINARY 类型 必须指定 (M) ,否则报错。
二进制字符串类型
特点
值的长度
占用空间
BINARY(M)
固定长度
M (0 <= M <= 255)
M 个字节
VARBINARY(M)
可变长度
M (0 <= M <= 65535)
M+1 个字节

举例:

创建表:

CREATE TABLE test_binary1(
f1 BINARY ,
f2 BINARY ( 3 ),
# f3 VARBINARY,
f4 VARBINARY ( 10 )
);
添加数据:
INSERT INTO test_binary1(f1,f2)
VALUES ( 'a' , 'a' );
INSERT INTO test_binary1(f1,f2)
VALUES ( ' ' , ' ' ); # 失败
INSERT INTO test_binary1(f2,f4)
VALUES ( 'ab' , 'ab' );
mysql> SELECT LENGTH(f2),LENGTH(f4)
-> FROM test_binary1;
+------------+------------+
| LENGTH(f2) | LENGTH(f4) |
+------------+------------+
| 3 | NULL |
| 3 | 2 |
+------------+------------+
2 rows in set ( 0.00 sec)
BLOB 类型
BLOB 是一个 二进制大对象 ,可以容纳可变数量的数据。
MySQL 中的 BLOB 类型包括 TINYBLOB BLOB MEDIUMBLOB LONGBLOB 4 种类型,它们可容纳值的最大长度不同。可以存储一个二进制的大对象,比如 图片 音频 视频 等。
需要注意的是,在实际工作中,往往不会在 MySQL 数据库中使用 BLOB 类型存储大对象数据,通常会将图片、音频和视频文件存储到 服务器的磁盘上 ,并将图片、音频和视频的访问路径存储到 MySQL 中。
二进制字符串类型
值的长度
长度范围
占用空间
TINYBLOB
L
0 <= L <= 255
L + 1 个字节
BLOB
L
0 <= L <= 65535 (相当于 64KB
L + 2 个字节
MEDIUMBLOB
L
0 <= L <= 16777215 (相当于 16MB
L + 3 个字节
LONGBLOB
L
0 <= L <= 4294967295 (相当于 4GB
L + 4 个字节

举例:

CREATE TABLE test_blob1(
id INT ,
img MEDIUMBLOB
);
TEXT BLOB 的使用注意事项:
在使用 text blob 字段类型时要注意以下几点,以便更好的发挥数据库的性能。
BLOB TEXT 值也会引起自己的一些问题,特别是执行了大量的删除或更新操作的时候。删除这种值会在数据表中留下很大的" 空洞 " ,以后填入这些 " 空洞 " 的记录可能长度不同。为了提高性能,建议定期使用 OPTIMIZE TABLE 功能对这类表进行 碎片整理
② 如果需要对大文本字段进行模糊查询, MySQL 提供了 前缀索引 。但是仍然要在不必要的时候避免检索大型的BLOB TEXT 值。例如, SELECT * 查询就不是很好的想法,除非你能够确定作为约束条件的WHERE子句只会找到所需要的数据行。否则,你可能毫无目的地在网络上传输大量的值。
③ 把 BLOB TEXT 分离到单独的表 中。在某些环境中,如果把这些数据列移动到第二张数据表中,可以让你把原数据表中的数据列转换为固定长度的数据行格式,那么它就是有意义的。这会 减少主表中的碎片 ,使你得到固定长度数据行的性能优势。它还使你在主数据表上运行 SELECT * 查询的时候不会通过网络传输大量的BLOB TEXT 值。

11. JSON 类型

JSON (JavaScript Object Notation)是一种轻量级的 数据交换格式 。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。它易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。 JSON 可以将 JavaScript 对象中表示的一组数据转换为字符串,然后就可以在网络或者程序之间轻 松地传递这个字符串,并在需要的时候将它还原为各编程语言所支持的数据格式。
MySQL 5.7 中,就已经支持 JSON 数据类型。在 MySQL 8.x 版本中, JSON 类型提供了可以进行自动验证的JSON文档和优化的存储结构,使得在 MySQL 中存储和读取 JSON 类型的数据更加方便和高效。 创建数据表,表中包含一个JSON 类型的字段 js
CREATE TABLE test_json(
js json
);
向表中插入 JSON 数据。
INSERT INTO test_json (js)
VALUES ( '{"name":"songhk", "age":18, "address":{"province":"beijing",
"city":"beijing"}}' );
查询 t19 表中的数据。
mysql> SELECT *
-> FROM test_json;

 

当需要检索JSON类型的字段中数据的某个具体值时,可以使用“->”“->>”符号。

mysql> SELECT js -> '$.name' AS NAME,js -> '$.age' AS age ,js -> '$.address.province'
AS province, js -> '$.address.city' AS city
-> FROM test_json;
+----------+------+-----------+-----------+
| NAME | age | province | city |
+----------+------+-----------+-----------+
| "songhk" | 18 | "beijing" | "beijing" |
+----------+------+-----------+-----------+
1 row in set ( 0.00 sec)
通过 “->” “->>” 符号,从 JSON 字段中正确查询出了指定的 JSON 数据的值。

12. 空间类型

MySQL 空间类型扩展支持地理特征的生成、存储和分析。这里的地理特征表示世界上具有位置的任何东西,可以是一个实体,例如一座山;可以是空间,例如一座办公楼;也可以是一个可定义的位置,例如一个十字路口等等。MySQL 中使用 Geometry (几何) 来表示所有地理特征。 Geometry 指一个点或点的集合,代表世界上任何具有位置的事物。
MySQL 的空间数据类型(Spatial Data Type)对应于 OpenGIS 类,包括单值类型: GEOMETRY POINT 、LINESTRING、 POLYGON 以及集合类型: MULTIPOINT MULTILINESTRING MULTIPOLYGON 、GEOMETRYCOLLECTION 。
  • Geometry是所有空间集合类型的基类,其他类型如POINTLINESTRINGPOLYGON都是Geometry子类。
    • Point,顾名思义就是点,有一个坐标值。例如POINT(121.213342 31.234532)POINT(30 10)坐标值支持DECIMAL类型,经度(longitude)在前,维度(latitude)在后,用空格分隔。
    • LineString,线,由一系列点连接而成。如果线从头至尾没有交叉,那就是简单的 simple);如果起点和终点重叠,那就是封闭的(closed)。例如LINESTRING(30 10,10 30,40 40),点与点之间用逗号分隔,一个点中的经纬度用空格分隔,与POINT格式一致。
    • Polygon,多边形。可以是一个实心平面形,即没有内部边界,也可以有空洞,类似纽扣。最简单的就是只有一个外边界的情况,例如POLYGON((0 0,10 0,10 10, 0 10))
下面展示几种常见的几何图形元素:
  •  MultiPoint、MultiLineStringMultiPolygonGeometryCollection 4种类型都是集合类,是多个PointLineStringPolygon组合而成。
下面展示的是多个同类或异类几何图形元素的组合:
 

13. 小结及选择建议

在定义数据类型时,如果确定是 整数 ,就用 INT ; 如果是 小数 ,一定用定点数类型
DECIMAL(M,D) ; 如果是日期与时间,就用 DATETIME
这样做的好处是,首先确保你的系统不会因为数据类型定义出错。不过,凡事都是有两面的,可靠性好,并不意味着高效。比如,TEXT 虽然使用方便,但是效率不如 CHAR(M) VARCHAR(M)
关于字符串的选择,建议参考如下阿里巴巴的《Java开发手册》规范:
阿里巴巴《 Java 开发手册》之 MySQL 数据库:
  • 任何字段如果为非负数,必须是 UNSIGNED
  • 强制 】小数类型为 DECIMAL,禁止使用 FLOAT DOUBLE
  • 说明:在存储的时候,FLOAT DOUBLE 都存在精度损失的问题,很可能在比较值的时候,得到不正确的结果。如果存储的数据范围超过 DECIMAL 的范围,建议将数据拆成整数和小数并分开存储。
  • 强制 】如果存储的字符串长度几乎相等,使用 CHAR 定长字符串类型。
  • 强制 VARCHAR 是可变长字符串,不预先分配存储空间,长度不要超过 5000。如果存储长度大于此值,定义字段类型为 TEXT,独立出来一张表,用主键来对应,避免影响其它字段索引效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/450992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 7、8 HashMap源码详解与分析

文章目录 一、哈希表的简介二、JDK1.7 HashMap1、构造方法2、添加方法put()方法addEntry()方法 3、存在的问题 三、JDK1.8 HashMap1、红黑树TreeMap2、属性3、存储的结构4、构造方法5、添加方法put(K, V)方法resize扩容方法 5、putAll()方法6、移除方法remove&#xff08;Objec…

Salesforce官方_中文学习、考证资源

Salesforce将Trailhead描述为学习热门技能的有趣且免费的平台。该平台有助于缩小技能差距&#xff0c;是所有Salesforce用户的宝藏资源。 Trailhead适合所有学习者。它涵盖了适用于Salesforce任何角色的主题和学习模块&#xff0c;从管理员、开发人员、销售主管到最终用户。学…

数据库基础篇 《12.MySQL数据类型精讲》

1. MySQL中的数据类型 2. 整数类型 2.1 类型介绍 整数类型一共有 5 种&#xff0c;包括 TINYINT、SMALLINT、MEDIUMINT、INT&#xff08;INTEGER&#xff09;和 BIGINT。 它们的区别如下表所示&#xff1a; 2.2 可选属性 整数类型的可选属性有三个&#xff1a; 2.2.1 M …

【Python】【进阶篇】3、Django ORM模块精讲

目录 3、Django ORM模块精讲1. 什么是 ORM&#xff1f;2. Django中定义数据表1) 模型类2) 定义数据表 3. ORM 管理器对象4. ORM优势与不足 3、Django ORM模块精讲 Django 框架向我们提供了丰富的模块&#xff0c;避免程序员在开发的过程中重复“造轮子”&#xff0c;提高了开发…

Docker开发基础使用(针对开发者足够)

一.Docker概述 容器就是虚拟化吗&#xff1f; 是&#xff0c;但也不竟然。我们用一种简单方式来思考一下&#xff1a; 虚拟化使得许多操作系统可同时在单个系统上运行。 容器则可共享同一个操作系统内核&#xff0c;将应用进程与系统其他部分隔离开。 这意味着什么&#xf…

Kotlin 用于数据科学的基础库(深度学习、数据挖掘)

Kotlin 用于数据科学 从构建数据流水线到生产机器学习模型&#xff0c; Kotlin 可能是处理数据的绝佳选择&#xff1a; Kotlin 简洁、易读且易于学习。静态类型与空安全有助于创建可靠的、可维护的、易于故障排除的代码。作为一种 JVM 语言&#xff0c;Kotlin 提供了出色的性…

机器视觉工程师买车就买“宝马”车-德国制造-世界精工

世界离开德国,整个地球的制造业将会落后五百年。 说起德国制造 在光学领域最牛的卡尔蔡司公司是制造相机镜头的世界级企业。,在机器视觉行业里面公司Mvtec,我们机器视觉工程师大多数用的halcon,就是来自于德国Mvtec,电气工程师使用的西门子PLC,西门子是是全球电子电气工程及…

兼容性测试用例

兼容性测试用例 兼容性测试是软件测试中非常重要的一块&#xff0c;它主要测试两个方面&#xff1a; 1.同一软件系统&#xff0c;不同版本之间的兼容性 在实际项目中&#xff0c;我们会遇到多种不同版本的软件系统&#xff0c;比如 Windows和 Linux&#xff0c;甚至还有 Unix、…

操作系统原理 —— 什么是进程?进程由什么组成?有什么特征?(六)

进程的概念 在我小时候&#xff0c;刚刚接触电脑的时候&#xff0c;只会在浏览器中输入 4399 搜索小游戏玩一玩&#xff0c;到后来&#xff0c;我学会了安装游戏&#xff0c;然后知道安装完成之后&#xff0c;找到对应的 .exe 的图标就可以运行游戏。 好&#xff0c;那么什么…

2.数据库开发

二.数据库开发 1.开发数据库流程 2.数据库,数据表,数据字段的命名 3.数据库字符集和排序规则设置 4.数据表的引擎选择 二.数据库开发 1.开发数据库流程 ①建立数据库

虚幻图文笔记:面部动画基本原理以及在UE5中如何导入面部动画

0. 面部动画的基本原理 之前做过的项目没有涉及过面部动画&#xff0c;所以最这方面不是很了解&#xff0c;一直以为面部动画也是通过骨骼来驱动的&#xff08;理论上用骨骼驱动当然也是可以的&#xff09;&#xff0c;但很多时候面部动画更多是使用Morph Target&#xff08;有…

SLAM论文速递【SLAM—— PLD-SLAM:一种基于点线特征的室内动态场景RGB-D SLAM新方法—4.23(1)

论文信息 题目&#xff1a; PLD-SLAM:A New RGB-D SLAM Method with Point and Line Features for Indoor Dynamic Scene PLD-SLAM:一种基于点线特征的室内动态场景RGB-D SLAM新方法论文地址&#xff1a; https://www.mdpi.com/2220-9964/10/3/163发表期刊&#xff1a; ISPR…

MySQL数据落盘原理(redo、undo、binlog、2PC、double write等。)

文章目录 前言一、架构图1、MySQL架构图2、InnoDB架构图 二、落盘分析1.第一阶段2.第二阶段3.第三阶段4.第四阶段5.第五阶段6.第六阶段 前言 在上一章中我们聊到了事务有四大特性&#xff1a;原子性、一致性、隔离性、持久性。本篇文章就持久性重点聊一下&#xff0c;在高性能…

离子交换法处理含铬废水

含铬废水是从哪里来的&#xff1f; 含铬废水来自&#xff1a;冶金、化工、矿物工程、电镀、制铬、颜料、制药、轻工纺织、铬盐及铬化物的生产等一系列行业&#xff0c;都会产生大量的含铬废水。 含铬废水危害有多大&#xff1f; 1、铬化合物具有致癌作用&#xff1b; 2、铬…

做SSM项目的步骤和优化

SSM框架整合 这里说的SSM整合&#xff0c;主要说的是Spring和mybatis之间的整合。因为spring和springMVC都是spring生态系统中的框架&#xff0c;所以spring和springMVC之间的整合是无缝的整合&#xff0c;即&#xff0c;我们在不知不觉中&#xff0c;其实spring和springMVC已…

【C++】list的使用

文章目录 1. list的使用1. 构造函数2.迭代器的使用和数据访问3. 容量相关4. 数据修改1.数据插入2. 数据删除 5.其他接口 1. list的使用 首先&#xff0c;在使用list之前&#xff0c;我们得先了解list到底是个什么东西&#xff0c;查看文档可以了解到&#xff0c;list的底层是一…

使用EasyExcel导出模板并设置级联下拉及其原理分析

一、概述 项目中有时会遇到需要导出一个Excel模板&#xff0c;然后在导出的Excel中填充数据&#xff0c;最终再调用接口批量把Excel中的数据导入到数据库当中的需求。 其中级联下拉选择&#xff0c;手机号校验&#xff0c;性别校验等都是比较常见的校验。 这里就已上面三种情…

县级医院手术麻醉管理系统源码 医院手麻系统源码 C/S架构 系统成熟稳定完整二次开发

医院手麻系统详细功能介绍和说明&#xff1a; ▶手术管理功能包括&#xff1a;手术申请、手术安排、查看手术申请单、手术通知单、填写病人术前会诊记录、谈话记录、麻醉记录、手术记录、附加手术、术后信息及手术回顾等功能。 ▶手术麻醉管理系统包括&#xff1a;手术申请、…

openEuler 欧拉 安装Oracle19c数据库RPM包安装

一、准备工作 将安装部署包上传到服务器上&#xff0c;我安装包放到/home目录下 二、安装依赖包 yum -y install binutils compat-libcap1 compat-libstdc-33 compat-libstdc-33*.i686 elfutils-libelf-devel gcc gcc-c glibc*.i686 glibc glibc-devel glibc-devel*.i686 ksh…

“烧钱”的大模型:初探成本拆解与推理优化方法

编者按&#xff1a;大模型的成本问题一直以来是大家重点关注的问题&#xff0c;本文重点讨论了训练大型语言模型&#xff08;LLMs&#xff09;需要的成本&#xff0c;并简要介绍什么是LLM以及一些用于优化大模型推理表现的技术。 虽然很难准确预测LLMs未来会怎么发展&#xff0…