> For the complete documentation index, see [llms.txt](https://mysql.gitbook.teaho.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mysql.gitbook.teaho.net/schema-yu-shu-ju-lei-xing-you-hua/untitled-1.md).

# 数据类型选择与优化

数据库的基础设计是很重要的。因为，有误差或者错误的设计是会使维护成本骤增的，并可能影响数据库性能。

一般情况有几条准则：

1. 应该尽量选用可以正确存储数据的最小数据类型。

   因为，这会占用更少的空间（无论是内存、缓存、磁盘），并会减少处理时占用的CPU周期。
2. 选用简单的。

   简单的数据类型处理时通常需要更少的处理周期（有时甚至能减少空间）。比如：整型不用字符串类型的来存储。这是很明显的，整型的比较仅仅是转换成二进制的简单比较，而字符串的比较呢，则涉及到对字符集及其内在规则等等。
3. 尽量避免用NULL。

   也就是说在声明字段时声明为NOT NULL。因为，在书写SQL时有时会让我们不得不对NULL作额外的考虑。而且，索引会为NULL额外在每个记录下多加一个字节。当然，这更多只是一个优秀的习惯，将NULL转变成NOT NULL对性能的提升较小，在解决性能问题时，也不该是优先考虑优化的地方。

### 整数类型

整数类型可为：TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT。分别为8、16、24、32、64位存储空间。

那么它们的取值范围：

$$
-2 ^{n-1} \leq i  \leq  2^{n-1}-1
$$

注：在表结构声明中，形如：int(8)、bigint(15)等是基本没有任何作用，如此声明既不影响存储的长度，也不能作用于查询输出。

### 浮点类型

DECIMAL、FLOAT、DOUBLE。

FLOAT和DOUBLE的长度，截取文档的说明：

> The `FLOAT` and `DOUBLE` types represent approximate numeric data values. MySQL uses four bytes for single-precision values and eight bytes for double-precision values.

DECIMAL:

> MySQL stores `DECIMAL` values in binary format. See [Section 12.23, “Precision Math”](https://dev.mysql.com/doc/refman/8.0/en/precision-math.html).
>
> The declaration syntax for a [`DECIMAL`](https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html) column is `DECIMAL(`*`M`*,*`D`*). The ranges of values for the arguments are as follows:
>
> * *`M`* is the maximum number of digits (the precision). It has a range of 1 to 65.
> * *`D`* is the number of digits to the right of the decimal point (the scale). It has a range of 0 to 30 and must be no larger than *`M`*.
>
> &#x20;For a full explanation of the internal format of `DECIMAL` values, see the file `strings/decimal.c` in a MySQL source distribution.

这三者都可指定长度，但是通常应使用FLOAT或DOUBLE，因为，

* DECIMAL是存储为binary format的，在计算中会转换为DOUBLE。需要额外的开销。
* DECIMAL更占位置。
* 但是，DECIMAL在一些十分需要精度的场合可以应用。

### 字符串类型

这里主讲一下VARCHAR。VARCHAR是较常见的字符串存储形式。VARCHAR作为变长的字符串存储类型，能节省空间。其实没啥好说的。。

需要注意的点是：

1. VARCHAR需要1个或两个字节存储长度信息。
2. **VARCHAR在例如VARCHAR(5)和VARCHAR(50)这两种不长度的声明中，性能是有差异的。**&#x901A;常，声明短的更好。因为，MySQL在一些内部值，如临时表，会分配固定大小的块来保存值。

### 枚举类型

通常，将例如：性别类等一些不同值的字符串值，使用枚举来存储会是一个不错的选择。

{% hint style="info" %}
要注意，枚举实际存储的是一个整数值而非字符串。当用枚举类型来关联字符串查询，对性能有负面影响。
{% endhint %}

### 时间类型

主要讨论点，TIMESTAMP和DATETIME。除去特殊需要外，通常应尽量使用TIMESTAMP，因为它更节省空间。

其实，在我工作中有如下经验，假如你的程序是要求高性能运行时，应该使用TIMESTAMP，因为，TIMESTAMP更节省带宽，不仅是在与数据库集群进行大量数据传输，还在于和客户端进行传输，假如你的程序是持续、多节点、长期、高访问量下运行时，其所节约网络IO时间是可观的。而且，在我合作过的前端工程师中，大多更喜欢我返回TIMESTAMP类型。

其他类型就不叙述。

### 标识符列

标识符列，选用啥数据类型呢？

建议使用整数类型而不是UUID搭配字符串类型存储。

理由：

1. 字符串耗空间。经测试，插入约千万数据后的，两种类型的主键所占磁盘空间整数类型比UUID字符串少一半。有兴趣的朋油可以自行测试。
2. 计算查询效率。请阅读本文开头准则中的举例，不赘叙。
3. UUID字符串如果作为缓存会使缓存的访问局部性原理失效。

#### 说几点零碎的：

* FLAG类型的列不太建议用bit类型。
* 某些特殊数据，比如：IP地址，其实可用整数类型存储。又比如特定的业务场景：某些时候的权限标识可用数字存储方便运算、又比如打卡记录可利用INT是2的32的特性等等。这些都是需要平时自己留意的。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mysql.gitbook.teaho.net/schema-yu-shu-ju-lei-xing-you-hua/untitled-1.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
