# 选择标识符

一般来说，<mark style="color:blue;">**标识符是引用行及通常使其唯一的方式**</mark>。例如，如果你有一个关于用户的表，可能希望为每个用户分配一个数字 ID 或唯一的用户名，此字段可能是主键中的部分或全部。

## 重要性

为标识符列选择合适的数据类型非常重要：

* 与其他列相比，更有可能将标识符列与其他值（例如，在联接中）进行比较，并使用它们进行查找。
* 标识符列也可能在其他表中作为外键，因此为<mark style="color:orange;">**标识符列选择数据类型时，应该与联接表中的对应列保持一致。**</mark>

## 遵循的原则

进行标识符选择的时候应该遵循以下原则：

1. <mark style="color:orange;">**在为标识符列选择类型时，不仅需要考虑存储类型，还需要考虑 MySQL 如何对该类型执行计算和比较**</mark>。例如，MySQL 在内部将 [***ENUM 和 SET***](/ji-chu/mysql/sql-you-hua/schema-she-ji/xuan-ze-shu-ju-lei-xing/zi-fu-chuan-lei-xing/enum-he-set.md) 类型存储为整数，但**在字符串上下文中进行比较时，会将它们转换为字符串**。
2. 选择类型后，<mark style="color:orange;">**要确保在所有相关表中使用相同的类型。**</mark>**类型应该完全匹配，包括&#x20;**<mark style="color:blue;">**UNSIGNED**</mark>**&#x20;等属性**。混合不同的数据类型可能导致性能问题，即使没有性能影响，在进行比较操作时，隐式类型转换也可能会产生难以发现的错误。甚至在很久以后，当你忘记正在比较不同类型的数据时，这些问题可能会突然出现。
3. 在可以满足值的范围的需求，并且预留未来增长空间的前提下，应该<mark style="color:orange;">**选择最小的数据类型**</mark>**。**
4. <mark style="color:orange;">**整数通常是标识符的最佳选择**</mark>，因为它们**速度快**，并且可以**自动递增**。**AUTO\_INCREMENT** 是一个列属性，可以为新的行自动生成一个整数类型的值。
5. 如果使用 ENUM 字段来定义类型，可能会设计一张**以这个 ENUM 字段为主键的查找表**。（可以在查找表中添加描述性文本的列，以生成术语表，或者在网站上的下拉菜单中提供有意义的标签。）在这种情况下，使用 ENUM 类型作为标识符是可行的，但是<mark style="color:orange;">**大部分情况下都要避免这么做**</mark>。
6. 如果可能，<mark style="color:orange;">**应避免使用字符串类型作为标识符的数据类型**</mark>，因为它们**很消耗空间**，而且**通常比整数类型慢**。

{% hint style="warning" %}

## <mark style="color:orange;">注意</mark>

<mark style="color:orange;">**对于完全“随机”的字符串要非常小心**</mark>，如 <mark style="color:blue;">**MD5()**</mark>、<mark style="color:blue;">**SHA1()**</mark> 或 <mark style="color:blue;">**UUID()**</mark> 生成的字符串。这些函数生成的新值会任意分布在很大的空间内，这会减慢 **INSERT** 和某些类型的 **SELECT** 查询的速度，因为：

* **插入的值会写到索引的随机位置**，所以会使得 INSERT 查询变慢。这会导致页分裂、磁盘随机访问，以及对于**聚簇**存储引擎产生聚簇索引碎片。
* SELECT 查询也会变慢，因为**逻辑上相邻的行会广泛分布在磁盘和内存**中。
* **对于所有类型的查询，随机值都会导致缓存的性能低下，因为它们会破坏引用的局部性，而这正是缓存的工作原理**。如果整个数据集都是“热的”，那么将任何特定部分的数据缓存到内存中都没有任何好处，而且如果工作集比内存大，缓存就会出现大量刷新和不命中。

<mark style="color:orange;">**如果存储通用唯一标识符(UUID)值，则应该删除破折号，或者更好的做法是，使用 UNHEX() 函数将 UUID 值转换为 16 字节的数字，并将其存储在一个 BINARY(16) 列中。可以使用 HEX() 函数以十六进制格式检索值。**</mark>
{% endhint %}


---

# Agent Instructions: 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:

```
GET https://bohans.gitbook.io/ji-chu/mysql/sql-you-hua/schema-she-ji/xuan-ze-biao-shi-fu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
