一的purchase表。因为当前的订单一直在被检索:它们的状态在被更新,由于客户经常查看订单的信息。另一方面,完成的订单只会被作为历史数据保存。它们很少被更新或者检索,所以可以在这张表上安排更长的访问时间。订单分离之后,经常使用的表能保持比较小,但我们仍然保存着所有数据。
?
类似地,你应当优化频繁更新的数据。想象一个系统的部分用户信息经常由另一个外部系统(例如,该外部系统计算同一类的奖励积分)更新。在我们的user表中也有其它信息,如他们的登陆账号、密码和全名。这些基本信息也经常被检索。频繁更新降低了获取用户基本信息的速度。最简单的解决方案就是把这些数据分离到两个表里面:一个记录基本信息(经常被读取),另一个记录奖励积分相关的信息(频繁被更新)。这样更新操作不会减缓读的操作。
?
分离频繁和不频繁使用的数据到多个表中不是处理大数据量的唯一方法。例如,如果你希望书的描述(description字段)非常长,你可以使用应用级别的缓存,这样你不用经常检索这个重量级的数据。书的描述很可能保持不变,所以这是一个很好的可被缓存的候选对象。
?
提示:
?
你的客户必须使用业务、领域特定的知识,预估预期你将处理的
数据库中的数据量。
?
分离频繁更新和频繁读取的数据。
?
对重量级、更新少的数据考虑使用应用级别的缓存。
?
以下是修改后的书城模型:
5 ——忽略时区
?
如果书城是面向全世界的呢?客户来自世界各地并且使用不同的时区。管理时区的date和datetime字段算是跨国系统中一个重要的问题。
?
系统必须始终为用户呈现准确的日期和时间,最好是以他们自己的时区。
?
举例,特殊供应的过期时间(这是任何商城中最重要的功能)必须让所有用户理解一致。如果你只是说“促销于12月24日结束”,他们会假定是在自己时区的12月24日半夜12点结束。如果你是指自己所在时区的圣诞前夜午夜12点,你必须说“12月24日,23.59 UTC”(即无论你的时区是什么)。对于某些用户,它将是“December 24, 19.59”,对另外一些用户则是“December 25, 4.49”。用户必须看到以他们所在时区为准的促销时间。
?
在一个跨时区系统中日期列类型是不会有效存在的。它应当一直是一个timestamp类型。
?
当登录事件在跨时区系统中发生时,可以采取类似的方式。事件的时间应该总是以某个选中的时区为准的标准化方式记录的,例如UTC,因此你能够毫无疑问地将时间从老到新排序。
?
数据库必须与应用代码合作以备处理时区问题。各种数据库存储日期和时间的数据类型有所不同。某些类型存储时间时带有时区信息,而有些则没有。程序员应当在系统中开发标准化的
组件来自动处理时区问题。
?
提示:
?
检查你的数据库中日期和时间数据类型的细节。SQL Server中Timestamp与PostgreSQL的timestamp完全不同。
?
用UTC的方式存储日期与时间。
?
处理好时区问题需要数据库和应用代码直接的合作。确保你理解了数据库驱动的细节。这里有相当多的陷阱。
?
6 ?——缺少审计跟踪
?
如果有人删除或者修改了我们书城中的一些重要数据,可我们在3个月之后才发现,发生了什么事情?我认为我们遇到了严重的问题。
?
也许我们有3个月前的一个备份,所以可以恢复备份到一些新的数据库以访问到数据。此后我们将有一个契机来恢复这些数据避免损失。但是为完成这个过程,必须满足许多因素
?
我们需要拥有那个合适的备份——哪一个才是合适的?
?
我们必须成功寻找到数据,
?
我们必须能不费太大力气就恢复数据。
?
当我们最终恢复了数据(但确定这就是最正确的版本吗?),就面临第二个问题——谁干的?谁在三个月前毁掉了数据?他们的IP/用户名是多少?我们如何核实?为了确定这一点,我们需要:
?
至少保存3个月的
系统访问日志——这不太有希望,它们或许可能已经被轮转替换了。
?
可以把删除数据的情况与访问日志中的某些URL关联起来。
?
这无疑会花费大量时间,而且没有多大成功的胜算。
?
我们的模型所缺失的,就是某种意义上的审计跟踪。有许多方式来达到这个目标:
?
数据库中的表可以有创建和更新时间戳,及所创建/修改行的用户标示。 完整的审计日志可以用触发器或者其它对正在使用的数据库管理系统有效的机制来实现。一些审计日志可以存储在单独的数据库以确保无法修改和删除,
?
数据能够防止数据丢失,通过:
?
不删除它,而是打上一个被删除的标记,
?
版本化修改。
?
按照惯例,保持黄金分割是最好的方式。你应当在数据安全和模型简易性中找到平衡。保存版本和记录事件使得数据库更复杂。忽略数据安全可能导致意外的数据丢失或者恢复丢失数据的高成本。
?
提示:
?
考虑哪个数据重要到需要跟踪修改/版本化,
?
考虑风险和成本之间的平衡;记住帕雷托定律指出大约80%的影响来自20%的原因;不要在不太可能的事故场景中保护你的数据,关注那些可能发生的场景。
?
这是对purchase和archived_purchase表加了基本审计跟踪功能的书城模型。
模型中的修改如下(以purchase表为例):
?
7 ?——忽略排序规则
?
最后的错误是一个棘手的问题,因为它只出现在一些系统中,主要是在多语种系统里。将它添加在这里,是因为我们经常遇到它,但它似乎并不广为人知。
?
通常来说,根据字母在字母表中的顺序,我们假定在一种语言中对单词排序与逐字排序一样容易。但是这里有两种陷阱:
?
首先,哪个字母表?如果我们的内容只有一种语言,那很显然,但是如果内容中有15到30种语言,该由哪一个字母表来决定顺序?
?
其次,当重音起作用时,逐字排序有时会有错误。
?
我们将在这个法文的简单SQL查询中举例说明:
?
db=# select title from book where id between 1 and 4 order by title collate "POSIX";
?title?
-------
?cote
?coté
?c?te
?c?té
?
这是逐字排序的结果,从左到右。
?
但是这些单词是法语,所以这才是正确的:
?
db=# select title from book where id between 1 and 4 order by title collate "en_GB";
?title?
-------
?cote
?c?te
?coté
?c?té
?
这两个结果不同,因为正确的单词顺序由排序规则决定——法语中的排序规则是在给定的单词中最后一个重音决定顺序。这是该特殊语言的一个特点。因此—— 语言的内容可以影响排序结果,而忽略语言会导致意想不到的排序结果。
?
提示: