schema 设计

schema 的设计原则

  1. 尽量避免在设计中出现极端情况,例如,强制执行非常复杂的查询或者包含很多列的表设计(很多的意思是介于有点多和非常多之间)。

  2. 使用小的、简单的、适当的数据类型,并避免使用 NULL。

  3. 尝试使用相同的数据类型来存储相似或相关的值,尤其是在联接条件中使用这些值时。

  4. 注意可变长度字符串,它可能会导致临时表排序的全长内存分配不乐观。

  5. 如果可能的话,尝试使用整数作为标识符

  6. 避免使用一些传统的 MySQL 技巧,例如,指定浮点数的精度整数的显示宽度

  7. 小心使用 ENUM 和 SET 类型。它们很方便,但也可能被滥用,有时还很棘手。另外最好避免使用 BIT 类型。

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

设计陷阱

太多的列

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

太多的联接

所谓的实体属性值(entity attribute value,EAV)设计模式是一种被普遍认为糟糕的设计模式的典型案例,尤其是在 MySQL 中效果不佳。

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

一个粗略的经验法则是,如果需要以高并发性快速执行查询,那么每个查询最好少于十几个的表。

NULL 不是虚拟值

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

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

当心自动生成的 schema

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

如果 schema 是自动生成的,一定要反复检查确认没有问题。

对象关系映射(ORM)系统(以及使用它们的“框架”)通常是另一个性能“噩梦”。其中一些 ORM 系统会将任意类型的数据存储到任意类型的后端数据存储中,这通常意味着其没有设计使用更优的数据存储。

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

最后更新于