> 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.md).

# schema 设计

## schema 的设计原则

1. <mark style="color:orange;">**尽量避免在设计中出现极端情况**</mark>，例如，强制执行非常复杂的查询或者包含很多列的表设计（很多的意思是介于有点多和非常多之间）。
2. <mark style="color:orange;">**使用小的、简单的、适当的数据类型，并避免使用 NULL。**</mark>
3. 尝试<mark style="color:orange;">**使用相同的数据类型来存储相似或相关的值**</mark>，尤其是在<mark style="color:orange;">**联接条件**</mark>中使用这些值时。
4. 注意<mark style="color:orange;">**可变长度字符串**</mark>，它可能会导致**临时表**和**排序**的全长内存分配不乐观。
5. 如果可能的话，尝试<mark style="color:orange;">**使用整数作为标识符**</mark>。
6. **避免**使用一些传统的 MySQL 技巧，例如，**指定浮点数的精度**或**整数的显示宽度**。
7. 小心使用 ENUM 和 SET 类型。它们很方便，但也可能被滥用，有时还很棘手。另外最好避免使用 BIT 类型。

> 请记住，<mark style="color:orange;">**你的 schema 将随着业务需求和用户数据而发展，这意味着拥有一个强大的软件生命周期来管理 schema 更改是使这种发展在组织中安全且可扩展的关键部分。**</mark>

## 设计陷阱

### <mark style="color:red;">**太多的列**</mark>

<mark style="color:blue;">**MySQL 的存储引擎 API 通过在服务器和存储引擎之间以行缓冲区格式复制行来工作**</mark>；然后，服务器将缓冲区<mark style="color:blue;">**解码**</mark>为列。将行缓冲区转换为具有解码列的行数据结构的操作代价是非常高的，而这种<mark style="color:orange;">**转换的成本取决于列数**</mark>。

### <mark style="color:red;">**太多的联接**</mark>

<mark style="color:blue;">**所谓的实体属性值（entity attribute value，EAV）设计模式是一种被普遍认为糟糕的设计模式的典型案例，尤其是在 MySQL 中效果不佳。**</mark>

MySQL 限制每个联接有 61 个表，而 EAV 模式设计的数据库需要许多自联接。

> <mark style="color:orange;">**一个粗略的经验法则是，如果需要以高并发性快速执行查询，那么每个查询最好少于十几个的表。**</mark>

### <mark style="color:red;">**NULL 不是虚拟值**</mark>

**当需要表示未知值时，不要太害怕使用 NULL**。

在某些情况下，使用 NULL 比使用某个虚拟常数更好。从受约束类型的域中选择一个值，例如使用 -1 表示一个未知的整数，可能会使代码复杂化，容易引入 bug，并通常会把事情搞得一团糟。处理 NULL 并不容易，但通常比其他替代方案更好。

### <mark style="color:red;">**当心自动生成的 schema**</mark>

写得不好的 **schema 迁移程序**和**自动生成 schema 的程序**可能会导致严重的性能问题。有些程序存储任何数据都会使用很大的 **VARCHAR** 字段，或者对将在联接中进行比较的列使用不同的数据类型。

{% hint style="warning" %} <mark style="color:orange;">**如果 schema 是自动生成的，一定要反复检查确认没有问题。**</mark>
{% endhint %}

> <mark style="color:blue;">**对象关系映射（ORM）系统**</mark>（以及使用它们的“框架”）通常是另一个性能“噩梦”。其中一些 ORM 系统会将任意类型的数据存储到任意类型的后端数据存储中，这通常意味着其没有设计使用更优的数据存储。

> <mark style="color:blue;">**“对开发人员隐藏复杂性”的应用程序通常不能很好地扩展。**</mark>建议在用性能交换开发人员的效率之前仔细考虑，并**始终在实际的大型数据集上进行测试**，这样就不会太晚才发现性能问题。
