> For the complete documentation index, see [llms.txt](https://bohans.gitbook.io/ji-chu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bohans.gitbook.io/ji-chu/mysql/sql-you-hua/schema-she-ji/xuan-ze-biao-shi-fu.md).

# 选择标识符

一般来说，<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 %}
