MySQL 8 数据类型详解

在上一章中,我们学习了如何使用 MySQL 8 命令行程序和工具在 MySQL 8 数据库上执行各种操作。掌握命令行工具总是好的。它提供了在非 GUI 环境中工作的灵活性。本章的重点是数据类型。了解编程语言支持的数据类型或存储引擎可以存储的数据类型不是很有趣吗?它是任何编程语言或数据库的基本特性。同时,它也是最容易被忽视的话题。大多数程序员没有花足够的时间评估一段代码中使用的variables的存储需求。实际上,了解数据库支持的基本和自定义数据类型非常重要,这就是本章存在的原因。

以下是本章将涵盖的主题列表:

MySQL 支持所有标准 SQL 数据类型。这些数据类型分为几个类别,例如数字类型、字符串类型、日期和时间类型以及 JSON 数据类型。当我们为列指定数据类型时,必须遵循某些约定。MySQL 需要以下约定才能允许将值存储在列中:

  • M表示整数类型的最大显示宽度。对于浮点和定点类型,它是可以存储的总位数。对于字符串类型,它是最大长度。允许的最大值取决于数据类型。
  • D适用于浮点型和定点型。它表示小数点后的位数。最大允许值为 30,但必须小于或等于 M-2。
  • fsp适用于日期和时间类型。它表示小数秒精度,这意味着小数点后秒的小数部分的位数。

此概述非常简短,因此可以在后面的主题中详细介绍每种数据类型的功能。

MySQL 8 数字数据类型包括整数或精确数据类型、十进制或近似数据类型以及位数据类型。

By default, REAL data type values are stored as DOUBLE. If we have set the REAL_AS_FLOAT flag on MySQL, REAL data type values are stored as FLOAT. FLOAT occupies less space compared to DOUBLE.

MySQL 支持所有标准 SQL 整数类型。

下表描述了每种整数类型所需的存储和范围。MySQL 除了支持标准整数数据类型外,还支持TINYINTMEDIUMINTBIGINT

| | 存储(字节) | 最小值 | 最大值 | | | | 已签字/未签字 | 已签字/未签字 | | TINYINT | 1. | -128 | 127 | | | | 0 | 255 | | SMALLINT | 2. | -32768 | 32767 | | | | 0 | 65535 | | MEDIUMINT | 3. | -8388608 | 8388607 | | | | 0 | 16777215 | | INT | 4. | -2147483648 | 2147483647 | | | | 0 | 4294967295 | | BIGINT | 8. | -9223372036854775808 | 9223372036854775807 | | | | 0 | 18446744073709551615 |

Reference: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html

有符号数字的范围包括-ve 和+ve 数字,而无符号数字的范围仅包括+ve 数字。

以下是无符号整数列的列声明:

CREATE TABLE employees
(salary INTEGER(5) UNSIGNED);

INTINTEGER可以互换使用。但是,如果我们宣布一列为:

CREATE TABLE employees
(id INT(255));

INTEGER列可以存储的最大值为 2147483647(对于有符号的INTEGER而言)或 4294967295(对于无符号的INTEGER255在此定义了数字的可见长度。一方面,显示一个长为255的数字是不切实际的。另一方面,INTEGER支持 10 位数字作为最大值。因此,在前一种情况下,它将转换为INT(11)。现在,这提出了另一个问题:如果最大整数的位数是 10,那么为什么要将其转换为INT(11)而不是INT(10)?原因是保留了一个数字用于存储标志。

ZEROFILL是一个属性,表示如果数值的长度小于列的长度,则数值应以零作为前缀。CREATE语句演示了一种使用ZEROFILL属性声明列的方法。以下是一个例子:

CREATE TABLE documents
(document_no INT(5) ZEROFILL);

我们将要存储的值指定为111;如果我们提供了ZEROFILL选项,它将被存储为00111

定点类型表示小数点或小数点后有固定位数的数字。MySQL 有DECIMALNUMERIC作为定点或精确值数据类型。这些值以二进制格式存储。定点数据类型非常有用,尤其是在乘法和除法运算中存储货币值时。定点数据类型的值是根据类型按特定因子缩放的整数。例如,1.11 的值可以在固定点中表示为111,比例因子为 1/100。类似地,1110000 可以表示为1110,比例因子为 1000。

以下代码块演示了DECIMAL数据类型的声明:

CREATE TABLE taxes
(tax_rate DECIMAL(3, 2));

在上例中,3是精度,2是刻度。示例值可以是 4.65,其中4是精度,65是刻度:

  • 精度:表示为数值存储的有效位数
  • 刻度:表示小数点后的位数

精度和比例定义可存储在列中的值的范围。因此,在前一列声明中,tax_rate可以存储介于-9.99 和 9.99 之间的值。

在标准 SQL 中定义DECIMAL类型的语法如下:

DECIMAL(M)

在 MySQL 中,这相当于:

DECIMAL(M, 0)

DECIMAL声明一列相当于 MySQL 中的DECIMAL(M, 0)

In MySQL, 10 is the default value for M, if it's not provided.

DECIMAL类型支持的最大位数为 65,包括精度和刻度。我们可以使用精度和比例来限制可以为列输入的值的位数。如果用户输入的值的位数大于允许的比例,则该值将被截断以匹配允许的比例。

DECIMAL通常被认为是DOUBLEFLOAT的替代品。如前所述,DECIMAL数字是REAL数字在数学中的精确表示。DECIMAL数据类型的唯一问题是它占用了更多的空间,即使是对于小数字也是如此。例如,要存储值 0.000003,列声明的数据类型应定义为DECIMAL(7, 6)

如果刻度为0,则列值没有小数点或小数点。

浮点数表示计算中的实数。实数用于测量连续值,例如体重、身高或速度。

MySQL 有两种用于存储近似值的浮点数据类型:FLOATDOUBLE

对于浮点数,精度是一个重要因素。精度定义了精度的度量。MySQL 支持单精度和双精度浮点数。使用FLOAT数据类型存储单精度浮点数需要四个字节,而使用DOUBLE数据类型存储双精度浮点数需要八个字节。

在 MySQL 中,REALDOUBLE PRECISION的同义词。如前所述,如果启用了REAL_AS_FLOAT,则使用REAL数据类型定义的列将被类似于FLOAT处理。

前面的描述将FLOATDOUBLE描述为类似于DECIMAL。不,不是。这是一个巨大的差异。如前所述,DECIMALNUMERIC等定点数据类型可存储精确值,最多可存储小数点后的最大数字,而FLOATDOUBLE等浮点数据类型可存储近似值。存储的值足够详细,但并不完全准确。还有一点不准确。

让我们通过以下代码示例来理解这一点:

mysql> CREATE TABLE typed_numbers(id TINYINT, float_values FLOAT, decimal_values DECIMAL(3, 2));

mysql> INSERT INTO typed_numbers VALUES(1, 1.1, 1.1), (2, 1.1, 1.1), (3, 1.1, 1.1);

mysql> SELECT * FROM typed_numbers;
+------+--------------+------------------+
| id   | float_values | decimal_values   |
+------+--------------+------------------+
|   1  |          1.1 |             1.10 |
|   2  |          1.1 |             1.10 |
|   3  |          1.1 |             1.10 |
+------+--------------+------------------+
mysql> SELECT SUM(float_values), SUM(decimal_values) FROM typed_numbers;
+--------------------+---------------------+
| SUM(float_values)  | SUM(decimal_values) |
+--------------------+---------------------+
| 3.3000000715255737 |                3.30 |
+--------------------+---------------------+

在前面的示例中:

  1. 我们创建了一个包含FLOATDECIMAL类型列的表。
  2. 我们在两列中插入了相同的值,分别为float_valuesdecimal_values
  3. 我们执行了一个select查询来获取存储值的总和。

虽然值相同,但输出不同。decimal_values的总和看起来比float_values的总和更精确。float_values的总和看起来不那么精确。这是因为 MySQL 引擎对浮点数据类型执行内部舍入,这会产生近似存储值。

标准 SQL 提供了定义FLOAT列时指定精度的规定。精度以括号内关键字FLOAT后面指定的位为单位。MySQL 还支持为FLOATDOUBLE指定精度值,但精度用于确定大小:

  • 从 0 到 23 的精度产生一个 4 字节的单精度FLOAT
  • 从 24 到 53 的精度产生一个 8 字节的双精度DOUBLE

以下是FLOAT列声明属性示例:

FLOAT(M, D) 
where,
M - number of digits in total
D - number of digits may be after the decimal point

因此,定义如下的列将存储一个值,如 99.99:

FLOAT(4, 2)

存储浮点值时,MySQL 执行舍入。因此,FLOAT(4, 2)列中插入为 99.09 的值可以存储为 99.01 作为近似结果。

Though the floating point column definition supports specifying precision, it is advisable to use FLOAT or DOUBLE PRECISION with no precision or number of digits, so as to take advantage of maximum flexibility and portability.

如前所述,浮点数据类型存储近似实数。尝试存储精确值并在考虑精确值的比较操作中使用它可能会导致各种问题。此外,浮点值以平台和实现依赖的方式进行解释。例如,不同的 CPU 或操作系统可能会对浮点数进行不同的计算。这本质上意味着要存储在浮点数据类型列中的值可能与内部存储或表示的实际值不同。

当我们在比较中使用浮点数时,上一个点变得至关重要。考虑下面的例子:

mysql> CREATE TABLE temp(id INT, col1 DOUBLE, col2 DOUBLE);

mysql> INSERT INTO temp VALUES (1, 5.30, 2.30), (1, -3.00, 0.00),
 (2, 0.10, -10.00), (2, -15.20, 4.00), (2, 0.00, -7.10),
 (3, 0.00, 2.30), (3, 0.00, 0.00);

mysql> SELECT id, SUM(col1) as v1, SUM(col2) as v2 FROM temp
 GROUP BY id HAVING v1 <> v2;
+------+--------+--------+
|  id  |   v1   |   v2   |
+------+--------+--------+
|    1 |    2.3 |    2.3 |
|    2 |  -15.1 |  -13.1 |
|    3 |    0.0 |    2.3 |
+------+--------+--------+

在前面的示例中,输出中的前两行似乎有相似的数字。在浮点类型的情况下,它们可能不是。在前面的例子中,如果我们想确保考虑到类似的外观值,我们必须将差异与预定义的数字进行精确比较。例如,在前面的例子中,如果我们修改HAVING子句来检查条件ABS(v1 - v2) > 0.1,它将返回预期的输出。

As interpretation of floating point numbers is platform dependent, if we try to insert a value which is outside of the range of floating point data type supported values, it may insert +- inf or +- 0.

您是否遇到过存储数字二进制表示的要求?你能想到这样的用例吗?一个这样的用例是存储一年的每周工作日信息。我们将在本节后面的示例中讨论这个基础。

BIT数据类型用于存储二进制位或位值组。它也是存储布尔值、是/否或0/1值的选项之一。

BIT型列可定义为:

column_name BIT
or
column_name BIT(m)
where m = number of bits to be stored

对于BIT数据类型,m可以从164不等。提供m是可选的。m的默认值为1

以下是如何定义BIT列的示例:

CREATE TABLE working_days (
year INT,
week INT,
days BIT(7),
PRIMARY KEY (year, week));

BIT数据类型列声明之后,接下来将在列中存储位值。位值是 0(0)和 1(1)的组合。b'value'符号用于指定位值。

以下是如何在BIT列中存储 11 和 55 的示例:

CREATE TABLE bit_values (val BIT(7));

INSERT INTO bit_values VALUES(b'1011');
INSERT INTO bit_values VALUES(b'110111');

如果BIT列中存储的值小于列定义中指定的位数(m,会发生什么情况?MySQL 将在数字左侧用 0 填充该值。因此,对于前面的示例,存储的值将分别为 0001011 和 0110111。

我们如何定义一个BIT列来存储boolean_values?以下代码块显示:

CREATE TABLE boolean_values (value BIT(1));
or
CREATE TABLE boolean_values (value BIT);

INSERT INTO boolean_values VALUES(b'0');
INSERT INTO boolean_values VALUES(b'1');

要在表列中存储位值,我们必须了解位文字。如前所述,位文字可以使用b'val'符号写入。还有另一种表示法,0bval表示法。

One important note about b'val' or 0bval notations is that the letter case of the leading b doesn't matter. We can specify b or B. A leading 0b is case-sensitive, and can't be replaced with 0B.

以下是合法和非法位值文字的列表。

合法位值文字:

  • b'10'
  • B'11'
  • 0b10

非法位值文字:

  • b'3'10是唯一的二进制数字)
  • 0B010B无效,应为0b

默认情况下,位文字是二进制字符串。我们可以通过查询来确认这一点,如下代码块所示:

mysql> SELECT b'1010110', CHARSET(b'1010110');
+--------------+----------------------+
| b'1010110'  | CHARSET(b'1010110') |
+--------------+----------------------+
|    V         |     binary           |
+--------------+----------------------+

mysql> SELECT 0b1100100, CHARSET(0b1100100);
+--------------+----------------------+
|  0b1100100   |  CHARSET(0b1100100)  |
+--------------+----------------------+
|    d         |     binary           |
+--------------+----------------------+

让我们继续一年中的每周工作日示例。请参考前面提供的working_days表架构。

如何确定20174周的周一和周五为非工作日?以下是对此的INSERT查询:

INSERT INTO working_days VALUES(2017, 4, 0111011);

如果我们使用SELECT查询获取working_days记录,则输出如下:

mysql> SELECT year, week, days FROM working_days;
+--------+---------+--------+
|  year  |   week  |  days  |
+--------+---------+--------+
|   2017 |       4 |     59 |
+--------+---------+--------+

在前面的输出中,天虽然是位数据类型,但显示整数值。如何在输出中显示位值?

答案是BIN()MySQL 函数。函数将整数值转换为其二进制表示形式:

mysql> SELECT year, week, BIN(days) FROM working_days;
+--------+---------+------------+
|  year  |   week  |    days    |
+--------+---------+------------+
|   2017 |       4 |    111011  |
+--------+---------+------------+

如您所见,前导零将从输出中的天位值中删除。为了完成输出中的表示,在BIN函数之上,我们可以使用LPADMySQL 函数:

mysql> SELECT year, week, LPAD(BIN(days), 7, '0') FROM working_days;
+--------+---------+------------+
|  year  |   week  |    days    |
+--------+---------+------------+
|   2017 |       4 |    0111011 |
+--------+---------+------------+

如前所示,在定义整数列时,我们还可以指定可选的显示宽度属性。例如,INT(5)表示显示宽度为5位的整数。在SELECT查询中使用此列时,输出将显示用空格填充的数字。因此,如果INT(5)列中存储的值为123,则显示为__123_将是实际输出中的一个空格。

但是,显示宽度并不限制可存储在INT(5)列中的值的范围。然后问题出现了:如果我们存储的值的显示宽度大于指定的显示宽度,该怎么办?显示宽度不会阻止比列的显示宽度宽的值正确显示。因此,比列显示宽度宽的值以全宽显示,使用的位数超过显示宽度指定的位数。

如前所述,MySQL 列定义提供了一个名为ZEROFILL的可选属性。指定此可选属性后,将用零替换左填充空格。例如,对于定义为以下内容的列,将值 82 检索为 00082:

INT(5) ZEROFILL

当数字的正确格式非常重要时,此可选属性非常有用。

The ZEROFILL attribute is ignored when the column value is used in expressions or in a UNION query.

MySQL creates temporary tables when complicated joins are used in a query to store intermediate results. In such a case, we may face issues if we specified a column with display width. In these cases, MySQL considers that the data values fit within the display width.

另一个重要属性是UNSIGNEDUNSIGNED属性只允许在列中存储非负值。当我们需要支持使用相同的数据类型存储更大范围的值时,它也很有用。

UNSIGNED还支持浮点类型和定点类型。

If we specify a ZEROFILL attribute for a column, UNSIGNED is automatically added to the column.

整数和浮点列的另一个重要属性是AUTO_INCREMENT。当我们在用AUTO_INCREMENT属性定义的列中插入NULL值时,MySQL 存储的是value+1而不是NULL。除非启用了NO_AUTO_VALUE_ON_ZERO模式,否则 0 的值将被视为与NULL值相同。此处,该值是存储在列中的最大值。将该列定义为NOT NULL非常重要。否则,即使提供了AUTO_INCREMENT属性,NULL值也将存储为NULL

当 MySQL 中的数值类型列中存储超出范围的值时,存储的值取决于 MySQL 模式:

  • 如果启用了strict模式,MySQL 将不接受该值并抛出错误。insert操作失败。
  • 如果启用了restrictive模式,MySQL 会将该值剪裁为适当的值,这就是存储在列中的值。

DATETIMEDATETIMETIMESTAMPYEAR构成了用于存储时间值的日期和时间数据类型组。每种类型都有一个允许值范围。除了允许的值外,还可以使用特殊的zero值指定 MySQL 无法表示的无效值。零值可以是 00-00-0000。MySQL 允许将此值存储在date列中。这有时比存储NULL值更方便。

以下是处理日期和时间类型时必须注意的一般事项。

MySQL 处理日期或时间类型的存储和检索操作的方式在格式的上下文中是不同的。基本上,对于表中存储的日期或时间类型的值,MySQL 以标准输出格式检索值。在输入日期或时间类型值的情况下,MySQL 尝试对提供的输入值应用不同的格式。因此,预期提供的值是有效的,或者如果以不支持的格式使用值,可能会出现意外结果。

尽管 MySQL 可以用几种不同的格式解释输入值,但部分日期值必须以年-月-日格式提供。例如,2017-10-22 或 16-02-14。

提供两位数的年份会使 MySQL 在解释年份时产生歧义,因为世纪未知。以下是必须遵循的规则,MySQL 使用这些规则解释两位数的年份值:

  • 70-99 之间的年份值转换为 1970-1999
  • 00-69 之间的年份值转换为 2000-2069

可以按照某些规则将值从一种时态类型转换为另一种时态类型。我们将在本章后面讨论这些规则。

如果在数字上下文中使用日期或时间值,MySQL 将自动将该值转换为数字。

我们有一个有趣的用例。我们希望开发一个审计日志功能,在其中存储每个用户输入的值。假设在其中一个日期字段中,用户输入了无效日期 2017-02-31。这将存储在审核日志表中吗?当然不是。那么,我们如何完成这项功能呢?MySQL 具有ALLOW_INVALID_DATES模式。如果启用,它将允许存储无效日期。启用此模式后,MySQL 将验证月份是否在 1-12 范围内,日期是否在 1-31 范围内。

As ODBC cannot handle zero values for date or time, such values used through Connector/ODBC are converted to NULL.

下表显示了不同数据类型的零值:

| 数据类型 | 零值 | | DATE | 0000-00-00 | | TIME | 00:00:00 | | DATETIME | 0000-00-00 00:00:00 | | TIMESTAMP | 0000-00-00 00:00:00 | | YEAR | 0000 |

Reference: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html

上表显示了不同时态数据类型的zero值。这些是特殊的值,因为 MySQL 允许这些值,并且在某些情况下非常有用。我们也可以使用'0'0指定zero值。MySQL 有一个有趣的模式配置:NO_ZERO_DATE。如果启用此配置,MySQL 将显示一条警告,如果时间类型具有日期为zero的值。

本节介绍最常用的 MySQL 日期和时间数据类型:DATEDATETIMETIMESTAMP。本节解释了这些数据类型之间的相似性和差异。

DATE数据类型适用于我们希望存储的值有日期部分,但缺少时间部分的情况。MySQL 的标准日期格式为 YYYY-MM-DD。除非应用了DATE函数,否则将以标准格式检索和显示日期值。MySQL 支持的值范围为 1000-01-01 到 9999-12-31。这里,支持意味着这些值可能有效,但不能保证。DATETIME数据类型的情况也是如此。

DATETIME数据类型适用于包含日期和时间部分的值。标准 MySQLDATETIME格式为 YYYY-MM-DD HH:MM:SS。支持的值范围为 1000-01-01 00:00:00 到 9999-12-31 23:59:59。

DATETIME类似,TIMESTAMP数据类型也适用于包含日期和时间部分的值。但是,TIMESTAMP数据类型支持的值范围是 1970-01-01 00:00:01 UTC 到 2038-01-19 03:14:07 UTC。

尽管它们看起来很相似,DATETIMETIMESTAMP数据类型却有显著差异:

  • TIMESTAMP数据类型需要 4 个字节来存储日期和时间值。DATETIME数据类型需要 5 个字节来存储日期和时间值。
  • TIMESTAMP可以存储值到 2038-01-19 03:14:07 UTC。如果我们希望存储 2038 之后的值,则应使用DATETIME数据类型。
  • TIMESTAMP在存储值时,将 UTC 视为时区。DATETIME存储不考虑时区的值。

让我们用一个例子来理解在time_zone的上下文中DATETIMETIMESTAMP之间的区别。

假设初始time_zone值设置为+00:00

SET time_zone = '+00:00';

让我们创建一个名为datetime_temp的表。该表有两列;一个是DATETIME型,另一个是TIMESTAMP型。我们将在两列中存储相同的日期和时间值。在SELECT查询的帮助下,我们将尝试了解表示在输出方面的差异:

mysql> CREATE TABLE datetime_temp(
 ts TIMESTAMP,
 dt DATETIME);

mysql> INSERT INTO datetime_temp
VALUES(NOW(), NOW());

mysql> SELECT ts, dt FROM datetime_temp;
+------------------------+-------------------------+
>|          ts            |            dt           |
+------------------------+-------------------------+
|  2017-10-14 18:10:25   |  2017-10-14 18:10:25    |
+------------------------+-------------------------+

在前面的示例中,NOW()是返回当前日期和时间值的 MySQL 函数。从输出来看,TIMESTAMPDATETIME表示似乎是相同的。这是因为time_zone值设置为 UTC。默认情况下,TIMESTAMP显示考虑 UTCtime_zone的日期时间值。在另一部分,DATETIME显示日期时间,没有time_zone

让我们更改time_zone并观察输出:

mysql> SET time_zone = '+03:00';

mysql> SELECT ts, dt FROM datetime_temp;
+------------------------+-------------------------+
|          ts            |            dt           |
+------------------------+-------------------------+
|  2017-10-14 21:10:25   |  2017-10-14 18:10:25    |
+------------------------+-------------------------+

从输出来看,TIMESTAMP显然考虑了 MySQL 中设置的time_zone值。因此,当我们改变时区时,TIMESTAMP值得到了调整。DATETIME没有受到影响,因此即使改变了时区,输出也没有改变。

If TIMESTAMP is used to store date and time values, we must consider it seriously when migrating data to a different server located in a different time zone.

如果需要更高的时间值精度,DATETIMETIMESTAMP可以包括小到微秒(六位数)的尾随分数秒。因此,如果我们插入一个带有微秒值的日期时间值,它将存储在数据库中。格式(包括小数部分)为 YYYY-MM-DD HH:MM:SS[.fraction],范围为 1000-01-01 00:00:00.000000 到 9999-12-31 23:59:59.99999。TIMESTAMP的范围(包括分数)为 1970-01-01 00:00:01.000000 至 2038-01-19 03:14:07.99999。

小数部分与时间值之间用一个小数点分隔,因为 MySQL 无法识别小数秒的任何其他分隔符。

使用TIMESTAMP数据类型存储的日期和时间值从服务器时区转换为 UTC 进行存储,从 UTC 转换为服务器时区进行检索。如果我们存储一个TIMESTAMP值,然后更改服务器的时区并检索该值,则检索到的值将不同于我们存储的值。

以下是 MySQL 中日期值解释的属性列表:

  • MySQL 对指定为字符串的值支持宽松格式。在宽松格式中,任何标点符号都可以用作日期部分或时间部分之间的分隔符。这有点令人困惑。例如,由于使用了:,值10:11:12可能看起来像时间值,但被解释为2010-11-12日期。
  • 在剩余时间部分和小数秒部分之间唯一可识别的分隔符是小数点。
  • 月和日的值应该是有效的。禁用strict模式时,无效日期将转换为相应的zero值,并显示警告消息。
  • TIMESTAMP日或月列中包含零的值不是有效日期。此规则的例外情况是zero值。

If MySQL is run with MAXDB mode enabled, TIMESTAMP is identical to DATETIME. If this mode is enabled at the time of table creation, TIMESTAMP values are converted to DATETIME.

NOW()是获取系统当前日期和时间的功能:

mysql> SET @dt = NOW();
mysql> SELECT @dt;
+---------------------+
|       @dt           |
+---------------------+
| 2017-10-15 13:43:17 |
+---------------------+

DATE()功能用于从DATETIME值中提取日期信息:

mysql> SELECT DATE(@dt);
+------------------+
|    DATE(@dt)     |
+------------------+
|    2017-10-15    |
+------------------+

TIME()功能用于从日期时间值中提取时间信息:

mysql> SELECT TIME(@dt);
+------------------+
|    TIME(@dt)     |
+------------------+
|     13:43:17     |
+------------------+

当您希望基于日期或时间值显示或查询数据库表时,DATE()TIME()函数非常有用,但表中存储的实际值包含日期和时间信息。

如果我们想从DATETIMETIMESTAMP值中提取YEARMONTHDAYQUARTERWEEKHOURMINUTESECOND信息,可以使用相应的功能:

mysql> SELECT
 HOUR(@dt),
 MINUTE(@dt),
 SECOND(@dt),
 DAY(@dt),
 WEEK(@dt),
 MONTH(@dt),
 QUARTER(@dt),
 YEAR(@dt);
+-----------+-------------+-------------+---------+----------+
| HOUR(@dt) | MINUTE(@dt) | SECOND(@dt) | DAY(@dt)| WEEK(@dt)| 
+-----------+-------------+-------------+---------+----------+
+------------+--------------+-----------+
| MONTH(@dt) | QUARTER(@dt) | YEAR(@dt) |
+------------+--------------+-----------+
+-----------+-------------+-------------+---------+----------+
|        13 |          43 |          17 |      15 |       41 | 
+-----------+-------------+-------------+---------+----------+
+------------+--------------+-----------+
|         10 |            4 |      2017 |
+------------+--------------+-----------+

MySQLDATETIMETIMESTAMP数据类型用于表示特定日期的特定时间。只存储一天中的时间或两个事件之间的时差如何?MySQL 的TIME数据类型就是为了这个目的。

存储或显示TIME数据类型值的标准 MySQL 格式为HH:MM:SS。时间值表示一天中的时间,小于 24 小时,但如前所述,TIME数据类型也可用于存储经过的时间或两个事件之间的时间差。因此,TIME列可以存储大于 24 小时的值。

MySQLTIME列定义如下:

column_name TIME;

TIME数据类型列中可存储的值范围为-838:59:59 到 838:59:59。

MySQLTIME列也可以存储分数秒部分,最高可达微秒(六位数),类似于DATETIME列。考虑到分数秒精度,值的范围从-838:59:59.000000 到 838:59:59.00000 不等。

MySQLTIME列也可以有一个可选值:

column_name TIME(N);
where N represents number of fractional part, which is up to 6 digits.

TIME值通常需要 3 个字节来存储。如果TIME值包含分数秒精度,则需要根据分数秒精度的数量增加字节。

下表显示了存储分数秒精度所需的额外字节数:

| 分数秒精度 | 存储(字节) | | 0 | 0 | | 1, 2 | 1. | | 3, 4 | 2. | | 5, 6 | 3. |

MySQL 支持TIME列的缩写值。MySQL 有两种不同的方法来解释缩写值:

  • 如果缩写值有一个冒号(:,MySQL 将其解释为一天中的时间。例如,11:12 被解释为 11:12:00,而不是 00:11:12。
  • 如果缩写值没有冒号(:),MySQL 会假定最右边的两个数字代表秒。这意味着该值被解释为经过的时间,而不是一天中的时间。例如,“1214”和 1214 被 MySQL 解释为 00:12:14。

小数点是 MySQL 接受的唯一分隔符,用于将小数秒精度与其余时间值部分分开。

默认情况下,MySQL 会将超出允许值范围的值剪裁到该范围的最近端点。例如,-880:00:00 和 880:00:00 存储为-838:59:59 和 838:59:59。无效的TIME值被转换为 00:00:00。由于 00:00:00 本身是一个有效的TIME值,因此很难知道该值 00:00:00 是故意存储的,还是从无效的TIME值转换而来的。

MySQL 接受字符串和数字值作为TIME值。

CURRENT_TIME()功能可用于查找服务器上的当前时间。也可以使用ADDTIMESUBTIME函数添加或减去时间值。例如,以下示例将服务器的当前时间增加两个小时:

mysql> SELECT 
 CURRENT_TIME() AS 'CUR_TIME',
 ADDTIME(CURRENT_TIME(), 020000) AS 'ADDTIME',
 SUBTIME(CURRENT_TIME(), 020000) AS 'SUBTIME';

+----------+-----------+-----------+
| CUR_TIME |  ADDTIME  |  SUBTIME  |
+----------+-----------+-----------+
| 10:12:34 |  12:12:34 | 08:12:34  |
+----------+-----------+-----------+

UTC_TIME()功能可用于获取 UTC 时间。

存储生产年份的首选数据类型是什么?MySQL 对此的回答是YEAR数据类型。YEAR数据类型需要 1 字节来存储年份信息。

YEAR列可以声明为:

manufacturing_year YEAR
or
manufacturing_year YEAR(4)

值得注意的是,早期的 MySQL 版本支持YEAR(2)类型的列声明。MySQL 8 已经停止了对YEAR(2)的支持。我们可能希望将旧的 MySQL 数据库升级到 MySQL 8 数据库。在后面的一节中,我们将解释从YEAR(2)YEAR(4)的迁移细节。

MySQL 以 YYYY 格式表示YEAR值。值的范围从 1901 到 2155 和 0000。

以下是YEAR值输入支持的格式列表:

  • 从 1901 到 2155 的四位数字。
  • 从 1901 到 2155 的四位字符串。
  • 一个或两个数字,范围从 0 到 99。YEAR从 1 到 69 的值转换为 2001 到 2069,从 70 到 99 的值转换为 1970 到 1999。
  • 范围为 0 到 99 的一位或两位字符串。YEAR从 1 到 69 的值转换为 2001 到 2069,从 70 到 99 的值转换为 1970 到 1999。
  • 插入数字 0 的显示值为 0000,内部值为 0000。如果要插入 0 并将其解释为 2000,则应将其指定为字符串 0 或 00。
  • 返回可接受值YEAR上下文的函数的结果,例如NOW()

MySQL 将无效的YEAR值转换为 0000。

如前所述,MySQL 8 不支持YEAR(2)类型。试图创建一个以YEAR(2)为数据类型的列将出现如下错误:

mysql> CREATE TABLE temp(year YEAR(2));
ERROR 1818 (HY000): Supports only YEAR or YEAR(4) column.

重建表的ALTER TABLE查询将自动将YEAR(2)转换为YEAR(4)。将数据库升级到 MySQL 8 数据库后,YEAR(2)列仍为YEAR(2),但查询有错误。

YEAR(2)迁移到YEAR(4)有多种方式:

  • 使用具有FORCE属性的ALTER TABLE查询将YEAR(2)列转换为YEAR(4)。不过,它不会转换值。如果ALTER TABLE查询应用于复制主机,复制从机将复制ALTER TABLE语句。因此,更改将在所有复制节点上可用。
  • 使用二进制升级,无需转储或重新加载数据,是将YEAR(2)升级到YEAR(4)的另一种方式。运行mysql_upgrade之后执行REPAIR_TABLE并将YEAR(2)转换为YEAR(4)而不改变值。与前面的备选方案类似,如果将其应用于复制主机,则将在复制从机中复制。

需要注意的一点是,在升级时,我们不能将YEAR(2)数据与mysqldump一起转储,并在升级后重新加载转储文件。该方法有可能显著改变YEAR(2)值。

YEAR(2)YEAR(4)迁移之前,必须检查应用程序代码:

  • 选择两位数字的YEAR值的代码。
  • 不处理数字0插入的代码。在YEAR(2)中插入0导致2000,而在YEAR(4)中插入0导致0000

哪种数据类型是表示值最广泛需要和使用的数据类型?字符串或字符数据类型;这很容易,对吧?MySQL 支持多种字符串数据类型,以满足不同的存储需求。字符串数据类型分为两类:固定长度和可变长度。CHARVARCHARBINARYVARBINARYBLOBTEXTENUMSET是 MySQL 支持的字符串数据类型。每种数据类型的存储要求都不同,稍后将在单独的一节中解释。

CHAR数据类型是 MySQL 中固定长度的字符串数据类型。CHAR数据类型通常使用可存储的最大字符数声明,如下所示:

data CHAR(20);

在前面的示例中,数据列可以存储能够存储最大字符数的字符串值。

CHARVARCHAR在许多方面相似,但存在一定差异。如果要存储的字符串值大小固定,则首选CHAR数据类型。与VARCHAR用于固定大小的字符串相比,它将提供更好的性能。

长度从 0 到 255 不等。CHAR列中的值不能超过创建表时声明的最大长度。如果字符串的长度小于允许的最大长度,MySQL 会在指定长度的右侧添加填充。检索时,将删除尾随空格。以下是一个例子:

mysql> CREATE TABLE char_temp (
 data CHAR(3)
);

mysql> INSERT INTO char_temp(data) VALUES('abc'), (' a ');

mysql> SELECT data, LENGTH(data) 
 FROM char_temp;
+-------+--------------+
| data  | LENGTH(data) |
+-------+--------------+
|  abc  |      3       |
+-------+--------------+
|   a   |      2       |
+-------+--------------+

正如我们在前面的示例中所看到的,第二条记录被插入为' a ',但在输出中,尾随空格被删除。因此,长度显示为2而不是3

大多数 MySQL 排序规则都有 pad 属性。它确定如何处理尾随空格以比较非二进制字符串。有两种类型的排序规则:PAD SPACENO PAD。在PAD SPACE排序的情况下,比较时不考虑尾随空格。比较字符串时不考虑尾随空格。

NO PAD排序的情况下,尾随空格被视为任何其他字符。以下是一个例子:

mysql> CREATE TABLE employees (emp_name CHAR(10));

mysql> INSERT INTO employees VALUES ('Jack');

mysql> SELECT emp_name = 'Jack', emp_name = 'Jack ' FROM employees;
+-------------------+--------------------+ 
| emp_name = 'Jack' | emp_name = 'Jack ' | 
+-------------------+--------------------+ 
|                1  |                 1  | 
+-------------------+--------------------+ 
mysql> SELECT emp_name LIKE 'Jack', emp_name LIKE 'Jack ' FROM employees; 
+----------------------+------------------------+ 
| emp_name LIKE 'Jack' | emp_name LIKE 'Jack '  | 
+----------------------+------------------------+ 
|                    1 |                      0 | 
+----------------------+------------------------+

LIKE是在WHERE子句中用于比较的 MySQL 操作符。它专门用于字符串中的模式搜索。将字符串值与LIKE运算符进行比较时,尾随空格非常重要。

If PAD_CHAR_TO_FULL_LENGTH mode is enabled, at the time of retrieval, the trailing spaces will not be removed.

MySQLVARCHAR数据类型是一种可变长度的字符串数据类型,最大长度为 65535 个字符。VARCHAR值由 MySQL 存储为一个或两个字节长度的前缀,以及实际数据。VARCHAR的实际最大长度以最大行大小为准,即所有列共享 65536 字节。

如果VARCHAR值需要小于 255 个字节,则使用一个字节确定长度前缀。如果该值需要超过 255 个字节,则两个字节用于确定长度前缀。

如果启用 MySQL 严格模式,并且要插入到CHARVARCHAR列值中的值超过最大长度,则会生成错误。如果禁用严格模式,该值将被截断为允许的最大长度,并显示警告。

CHAR数据类型不同,要存储在VARCHAR中的值没有填充。此外,检索值时不会删除尾随空格。

另一组 MySQL 字符串数据类型是BINARYVARBINARY。这些数据类型类似于CHARVARCHAR数据类型。CHAR/VARCHARBINARY/VARBINARY之间的一个重要区别是BINARY/VARBINARY数据类型包含二进制字符串而不是字符串。BINARY/VARBINARY使用二进制字符集和排序规则。BINARY/VARBINARYCHAR BINARYVARCHAR BINARY数据类型不同。基本区别在于所指的字符集和排序规则。

允许值的最大长度与CHARVARCHAR相似。唯一的区别是BINARYVARBINARY的长度是字节,而不是字符。

MySQL 如何比较二进制值?答案是,比较是基于值中字节的数值进行的。

CHAR/VARCHAR数据类型类似,如果值的长度超过列长度,则会截断值,并生成警告。这是在strict模式未启用的情况下。如果启用strict模式,则会产生错误。

BINARY使用填充值 0x00(零字节)将值右填充到指定的列长度。插入时会添加填充值,但检索时不会删除尾随字节。在比较BINARY值时,所有字节都被认为是重要的。这同样适用于ORDER BYDISTINCT操作员。零字节和空格与0x00<空格不同。以下是插入二进制值的示例:

mysql> CREATE TABLE temp(
 data BINARY(3));

mysql> INSERT INTO temp(data) VALUES('a ');

在这种情况下,'a '在插入时变为'a \0''a\0'转换为'a\0\0。检索时,值保持不变。

VARBINARY是可变长度字符串数据类型。与BINARY不同,对于VARBINARY,插入时不添加填充,检索时不剥离字节。与BINARY类似,与VARBINARY相比,所有字节都是重要的。

如果表的列上有唯一的索引,则在列中插入仅在尾随键盘字节数上不同的值将产生重复的键错误。例如,如果这样一个列包含'a '并且我们尝试插入'a\0',它将导致重复键错误。

下面的示例解释了比较中BINARY值的填充:

mysql> CREATE TABLE bin_temp (data BINARY(3));

mysql> INSERT INTO bin_temp(data) VALUES('c');

mysql> SELECT data = 'c', data = 'c\0\0' from bin_temp;
+------------+-------------------+
| data = 'c' |    data = 'c\0\0' |
+------------+-------------------+
|          0 |                 1 |
+------------+-------------------+

如果需要检索与指定值相同的值而不进行填充,则最好使用VARBINARY

如果检索到的值必须与为无填充的存储指定的值相同,则最好使用VARBINARYBLOB数据类型之一。

在什么情况下,我们需要将数据存储在二进制大对象BLOB列中?有什么想法吗?存储文件或图像,你说的?这部分是正确的。在我们决定将图像或文件存储在数据库或文件系统中之前,我们需要评估情况。如果文件存储在文件系统中并迁移到另一个操作系统,则文件指针可能会损坏。修复文件指针需要额外的努力。在这种情况下,最好将文件存储在数据库中。但是,如果我们在数据库中存储了大量阻塞的文件或图像数据,可能会影响性能。

BLOB是 MySQL 存储可变长度的大型二进制信息的解决方案。MySQL 有四种BLOB类型:TINYBLOBBLOBMEDIUMBLOBLONGBLOB。这些数据类型之间的唯一区别是我们可以存储的值的最大长度。这些数据类型的存储要求将在本章后面的章节中解释。

BLOB类似,TEXT数据类型为TINYTEXTTEXTMEDIUMTEXTLONGTEXT。其最大长度和存储要求与BLOB数据类型类似。

BINARY数据类型一样,BLOB值存储为字节字符串,并具有二进制字符集和排序规则。对列值的数值进行比较和排序。TEXT值存储为非二进制字符串

BLOBTEXT数据类型的情况下,如果该值包含多余的尾随空格,则不管 MySQL 模式如何,MySQL 都会截断并发出警告。MySQL 不会在插入时填充BLOBTEXT列值,也不会在检索时剥离字节。

对于索引的TEXT列,索引比较会在值的末尾添加尾随空格作为填充。因此,如果现有的TEXT值和要插入的TEXT值之间的唯一差异在后面的空格中,则在插入时可能会发生重复键错误。BLOB可视为VARBINARYTEXT可视为VARCHAR,数值长度不受限制。

以下是VARBINARYVARCHARBLOBTEXT的区别:

  • BLOBTEXT列上创建索引时,必须指定索引前缀长度
  • BLOBTEXT不能有默认值

BLOBTEXT值在内部表示为具有单独分配的对象,这与其他数据类型不同,其他数据类型的存储每列分配一次。

MySQL 提供了一种数据类型,在创建表时可以为其预定义允许值列表。数据类型为ENUM。如果我们想限制用户插入超出值范围的值,我们应该定义数据类型ENUM的列。MySQL 将用户输入的字符串值编码为ENUM数据类型的数字。

ENUM提供以下提到的好处:

  • 紧凑型数据存储
  • 可读查询和输出

以下是一个示例,展示了ENUM何时有用:

mysql> CREATE TABLE subjects (
 name VARCHAR(40),
 stream ENUM('arts', 'commerce', 'science')
);

mysql> INSERT INTO subjects (name, stream) VALUES ('biology','science'), ('statistics','commerce'), ('history','arts');
mysql> SELECT name, stream FROM subjects WHERE stream = 'commerce';
+------------+----------+
|    name    |  stream  |
+------------+----------+
| statistics | commerce |
+------------+----------+

mysql> UPDATE subjects SET stream = 'science' WHERE stream = 'commerce';

ENUM值需要一个字节的存储空间。在这个表中存储 100 万条这样的记录需要 100 万字节的存储空间,而VARCHAR列需要 600 万字节的存储空间。

以下是需要考虑的重要限制:

  • ENUM值在内部存储为数字。因此,如果ENUM值看起来像数字,文字值可能会与其内部索引号混淆。
  • 使用ORDER BY条款中的ENUM列需要格外小心。ENUM值根据列表顺序分配索引号。ENUM值根据其索引编号进行排序。因此,确保ENUM值列表按字母顺序排列非常重要。此外,该列应按词汇排序,而不是按索引号排序。
  • ENUM值必须是带引号的字符串文字。
  • 每个ENUM值都有一个以 1 开头的索引。空字符串或错误值的索引为 0。我们可以通过在WHERE子句中用enum_column_value = 0查询表来查找无效的ENUM值。NULL值的指标为NULL。索引是指数值在ENUM数值列表中的位置。
  • 创建表时,MySQL 会自动从ENUM成员值中删除尾随空格。检索时,ENUM列中的值显示在列定义中使用的大小写中。如果要在ENUM列中存储一个数字,则该数字将被视为可能值的索引。存储的值是具有该索引的ENUM值。对于带引号的数值,如果枚举值列表中没有匹配字符串,则仍将其解释为索引。
  • 如果一个ENUM列被声明包含NULL值,NULL值被认为是该列的有效值,NULL成为默认值。如果不允许使用NULL,则第一个ENUM值将成为默认值。

如果在数字上下文中使用ENUM值,则使用索引。以下是在数字上下文中使用ENUM值的查询示例:

mysql> SELECT stream+1 FROM subjects;
+--------------+
|   stream+1   |
+--------------+
|      4       |
|      3       |
|      2       |
+--------------+

MySQLSET是一种可以有零个或多个值的数据类型。在创建表时指定了允许的值列表。每个值必须在允许值列表中。多个集合成员由逗号(,分隔的值列表指定。SET最多可以有 64 个不同的成员。如果启用strict模式,则如果在列定义中发现重复值,则会生成错误。

必须注意SET成员值不包含逗号;否则,它们被解释为SET成员分隔符。

指定为SET('yes', 'no') NOT NULL的列可以具有以下任意值:

  • ''
  • 'yes'
  • 'no'
  • 'yes,no'

SET成员值中自动删除尾随空格。检索时,SET列值使用列定义中使用的字母大小写显示。

以下是在SET数据类型中插入值的示例:

mysql> CREATE TABLE temp(
 hobbies SET('Travel', 'Sports', 'Fine Dining', 'Dancing'));

mysql> INSERT INTO temp(hobbies) VALUES(9);

SET值作为位图存储在 MySQL 表中,其中每个元素由一位表示。在前一种情况下,SET中的每个元素都分配了一个位。如果行具有给定元素,则关联的位将为 1。由于这种方法,每个元素都有一个关联的十进制值。此外,由于位图,虽然只有四个值,SET将占用一个字节。下表对此进行了说明:

| 元素 | 设定值 | 十进制值 | | 长途行走 | 00000001 | 1. | | 体育 | 00000010 | 2. | | 美食 | 00000100 | 4. | | 跳舞 | 00001000 | 8. |

多个SET元素可以通过添加其十进制值来表示。在前一种情况下,十进制值 9 被解释为移动、跳舞。

SET数据类型不太常用。这是因为尽管它是一种字符串数据类型,但实现起来有点复杂。可以存储的值限制为 64 个元素。我们不能在SET值中添加逗号,因为逗号是标准的SET值分隔符。从数据库设计的角度来看,使用SET意味着数据库没有规范化。

JSON 代表 JavaScript 对象表示法。假设我们希望在数据库中存储 web 应用程序的用户首选项。通常,我们可以选择使用iduser_idkeyvalue字段创建一个单独的表。这对于少数用户来说可能很好,但是对于成千上万的用户来说,与它为 web 应用程序增加的价值相比,维护成本是无法承受的。

在 MySQL 中,我们可以利用 JSON 数据类型来满足这个需求。MySQL 支持原生 JSON 数据类型,这使得 JSON 文档能够高效存储。MySQL 支持自动验证存储在 JSON 列中的 JSON 文档。尝试存储无效的 JSON 文档会产生错误。存储在 JSON 列中的 JSON 文档将转换为内部格式。该格式为二进制格式,其结构使服务器能够通过键或数组索引直接查找subojbects或嵌套值,而无需读取其他值。

JSON 列不能有默认值。JSON 数据类型需要与LONGTEXTLONGBLOB类似的存储。与其他字符串数据类型不同,JSON 列不直接索引。

以下是在表中插入 JSON 值的示例:

mysql> CREATE TABLE users(
 user_id INT UNSIGNED NOT NULL,
 preferences JSON NOT NULL);

mysql> INSERT INTO users(user_id, preferences)
 VALUES(1, '{"page_size": 10, "hobbies": {"sports": 1}}');

mysql> SELECT preferences FROM users;
+---------------------------------------------------------+
|                   preferences                           |
+---------------------------------------------------------+
|    {"hobbies": {"sports": 1}, "page_size": 10}          |
+---------------------------------------------------------+

在前面的示例中,我们已经格式化了 JSON 值。作为替代,我们也可以使用内置的JSON_OBJECT功能。函数接受键/值对列表并返回 JSON 对象。例如:

mysql> INSERT INTO users(user_id, preferences)
 VALUES(2, JSON_OBJECT("page_size", 1, "network", JSON_ARRAY("GSM", "CDMA", "WIFI")));

前面的INSERT查询将插入 JSON 值{"page_size": 1, "network": ["GSM", "CDMA", "WIFI"]}。我们也可以使用嵌套的JSON_OBJECT函数。当传递一组值时,JSON_ARRAY函数返回一个 JSON 数组。

如果多次指定同一密钥,则仅保留第一个密钥/值对。对于 JSON 数据类型,将对对象键进行排序,并删除键/值对之间的尾随空格。JSON 对象中的键必须是字符串。

仅当 JSON 文档有效时,在 JSON 列中插入 JSON 值才会成功。如果 JSON 文档无效,MySQL 将生成一个错误。

MySQL 还有一个更重要、更有用的函数,它对 JSON 值进行操作。JSON_MERGE函数接受多个 JSON 对象并生成单个聚合对象。

JSON_TYPE函数将 JSON 作为参数,并尝试将其解析为 JSON 值。如果值有效,它将返回该值的 JSON 类型,否则将生成错误。

如果要更新存储在 JSON 数据类型中的 JSON 文档中的值,应该怎么做?其中一种方法是删除旧文档并插入带有更新的新文档。这种方法似乎不太好,对吧?MySQL 8.0 支持对存储在 JSON 数据类型列中的 JSON 文档进行部分就地更新。优化器要求更新必须满足以下条件:

  • 该列必须是 JSON 类型。
  • 三个功能中的一个,JSON_SET()JSON_REPLACE()JSON_REMOVE()可用于更新列。MySQL 不允许直接分配列值作为部分更新。
  • 输入列和目标列必须相同。例如,UPDATE temp SET col1 = JSON_SET(col2, 'one', 10)之类的语句不能作为部分更新执行。
  • 这些更改仅更新现有阵列或对象,并且不会向父对象或阵列添加新元素。
  • 替换值不得大于被替换的值。

本节介绍 MySQL 中不同数据类型的存储要求。储存要求取决于不同的因素。存储引擎表示数据类型,并以不同的方式存储原始数据。

表的最大行大小为 65535 字节,即使存储引擎能够支持较大的行。不包括BLOBTEXT数据类型。

下表说明了数字数据类型的存储详细信息:

| 数据类型 | 需要存储 | | TINYINT | 1 字节 | | SMALLINT | 2 字节 | | MEDIUMINT | 3 字节 | | INTINTEGER | 4 字节 | | BIGINT | 8 字节 | | FLOAT(p) | 如果0<=p<=24,则为 4 字节,如果25<=p<=53则为 8 字节 | | FLOAT | 4 字节 | | DOUBLE [precision]REAL | 8 字节 | | DECIMAL(M, D)NUMERIC(M, D) | 变化 | | BIT(M) | 约为(M+7)/8字节 |

Reference: https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html

下表说明了DATETIME数据类型的存储要求:

| 数据类型 | 需要存储 | | YEAR | 1 字节 | | DATE | 3 字节 | | TIME | 3 字节+小数秒存储 | | DATETIME | 5 字节+小数秒存储 | | TIMESTAMP | 4 字节+小数秒存储 |

下表说明了分数秒精度所需的存储:

| 分数秒精度 | 需要存储 | | 0 | 0 字节 | | 1, 2 | 1 字节 | | 3, 4 | 2 字节 | | 5, 6 | 3 字节 |

下表说明了字符串数据类型的存储要求:

数据类型 需要存储
CHAR(M) M×w字节,0<=M<=255,其中w为字符集中最大长度字符所需的字节数
BINARY(M) M字节,0<=M<=255
VARCHAR(M)VARBINARY(M L+1 字节,如果列值需要 0− 255 字节,L+2 字节,如果值可能需要超过 255 字节
TINYBLOBTINYTEXT L+1 字节,其中L<28
BLOBTEXT L+2 字节,其中L<216
MEDIUMBLOBMEDIUMTEXT L+3 字节,其中L<224
LONGBLOBLONGTEXT L+4 字节,其中L<232
枚举('value1','value2',…) 1 或 2 个字节,具体取决于枚举值的数量(最大值为 65535 个)
SET('value1','value2',...) 1、2、3、4 或 8 字节,具体取决于集合成员的数量(最多 64 个成员)

Reference: https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html

对于字符串数据类型,使用值的长度和长度前缀存储可变长度字符串。根据数据类型,长度前缀从一个字节到四个字节不等。

JSON 数据类型的存储要求与LONGBLOBLONGTEXT类似。但是,由于 JSON 文档以二进制表示形式存储,因此在存储 JSON 文档时会增加开销。

一般来说,我们应该使用最精确的类型来存储数据。例如,CHAR数据类型应用于存储长度从 1 到 255 个字符不等的字符串值。另一个例子是MEDIUMINT UNSIGNED应该用于存储从 1 到 99999 的数字。

以 65 位小数的精度执行基本操作,如additionsubtractionmultiplicationDECIMAL数据除法。

根据准确性或速度的重要性,应选择使用FLOATDOUBLEBIGINT中存储的定点值可用于更高的精度。

这些是一般性的指导原则,但使用正确的数据类型的决定应基于前面章节中为每种数据类型分别解释的详细特征。

这是一个有趣的章节,有重要的内容要学习,对吗?在本章中,我们了解了 MySQL 中数据类型的重要性。我们看到了 MySQL 数据类型的不同分类。我们深入学习并理解了每种数据类型的特征和规范。我们还学习了 MySQL 的数据操作功能,了解了 MySQL 的一些设置和模式。在本章后面的部分中,我们学习了数据类型的存储要求。最后,我们学习了选择正确数据类型的一般准则。

继续下一章,我们将学习 MySQL 数据库管理。本章将重点介绍服务器管理,了解 MySQL 服务器的基本构建块,如数据字典、系统数据库等。本章将解释如何在一台机器上运行多个服务器实例以及 MySQL 角色和权限。

教程来源于Github,感谢apachecn大佬的无私奉献,致敬!

技术教程推荐

推荐系统三十六式 -〔刑无刀〕

硅谷产品实战36讲 -〔曲晓音〕

如何设计一个秒杀系统 -〔许令波〕

从0开始学大数据 -〔李智慧〕

安全攻防技能30讲 -〔何为舟〕

Java业务开发常见错误100例 -〔朱晔〕

Web漏洞挖掘实战 -〔王昊天〕

商业思维案例笔记 -〔曹雄峰〕

结构写作力 -〔李忠秋〕