schema 的设计原则
尽量避免在设计中出现极端情况,例如,强制执行非常复杂的查询或者包含很多列的表设计(很多的意思是介于有点多和非常多之间)。
使用小的、简单的、适当的数据类型,并避免使用 NULL。
尝试使用相同的数据类型来存储相似或相关的值,尤其是在联接条件中使用这些值时。
注意可变长度字符串,它可能会导致临时表和排序的全长内存分配不乐观。
如果可能的话,尝试使用整数作为标识符。
避免使用一些传统的 MySQL 技巧,例如,指定浮点数的精度或整数的显示宽度。
小心使用 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 系统会将任意类型的数据存储到任意类型的后端数据存储中,这通常意味着其没有设计使用更优的数据存储。
“对开发人员隐藏复杂性”的应用程序通常不能很好地扩展。建议在用性能交换开发人员的效率之前仔细考虑,并始终在实际的大型数据集上进行测试,这样就不会太晚才发现性能问题。
最后更新于