2009年5月13日星期三

数据库设计建议,范式以及进一步

几乎每一个新人在初学关系型数据库设计的时候,都会接触到关系范式。但是,我还是见到了大量很离谱的设计。客观的说,背下关系范式,离一个合格的数据库设计师还差很远。设计工作总是在理想与现实之,规范与工艺之间妥协。建筑如是,造船如是,操作系统设计如是,数据库设计亦如是。
是的,你记得范式,你还记得反范式建议。你知道范式减少冗余,提高一致性;你还知道反范式可以方便编程。不幸的是,最终的结果总是遵守范式的做法使自己的应用层代码混乱,而反范式的企图使得数据库也陷入混乱。
这是谁的错?
不必太自责,设计工作是一个经验的积累过程。没有人天生就会做设计。天才与勤奋,是乘法关系。并不是你笨,只是天才对面的那个系数还不够大而已。
以下的一些经验,或许在你读完关系范式以后,可以抽空看一看 。世上没有魔法,读完这篇文章,并不会立即让你拥有多年设计经验。但是,这些在设计工作中积累的经验教训,应该可以帮助你少走一些弯路。

关于范式

关系范式并不邪恶,也不要把它想得太神秘,如果书本上的定义不能让你很快理解,不妨试着回答以下的问题:
字段还可以再分吗?分成两个或更多的字段以后,还能不能表达完整的含义?
字段的值是不是有限的几个离散的状态?
两个或若干个字段,能不能提取出来建立为一个数据字典?
如果表中某个字段依赖其他表,被依赖的字段是不是唯一的(最好是主键)?
查询中是否会出现超过两个表的Join?

将数据库设计与系统设计结合起来

数据库设计并不是一个孤立的过程,整个软件生命期中,各方面的工作应该有机结合。这方面我觉得ACCP过去的教材讲得还不错,至少思路是对的:
在做需求分析的时候,做Use Case。此时可以分析出应用层的功能接口,对于数据库的实体分类可以有一个大概的划定。例如,这个项目会需要一个工作流,这个项目会需要一个订单系统,或者一个文档库,等等。通常,每个子系统可以对应一个
在做概要设计的时候,出类关系和ER简图。通常来说,此时不能确定所有的字段,但是会有哪些表,有哪些主外键依赖,有哪些地方应该需要存储过程和触发器的辅助,等等。
详细设计时尽可能将数据库结构完全固定。尽管现代开发工具不断提升XP能力,重构越来越简单。数据库的重构仍然是一件牵一发而动全身的事情,毕竟数据库是信息存储的根本。大厦楼顶加个小花园容易,把地基下面的承重柱子拔出来换两根试试?

重视SQL

近年来ORM发展很快,几乎每个框架都要提供这个功能,以至于会有些菜鸟认为“ORM”会淘汰SQL语言。
这是一块试金石,如果你有这样的感觉,应该考虑认真评估一下自己在这个领域是不是太菜了。
SQL不是一种编程语言这么简单,SQL代表的是一种与应用开发语言完全不同的思想。面向集合,过程无关,着眼于规则定义。可以说,SQL是FP High Order计算的最成功应用,也可以说,SQL是一种静态强类型的MapReduce语言。
看,换上时髦的名词,会不会让你觉得它上等起来了?
在应用层语言惨烈竞争的同时,SQL语言压倒了同时代出现的其他关系型数据库操作语言,在这个拥有巨大利润的领域占据了绝对统治地位。即使桀骜不驯的Postgres,也在1995年变身为PostgrSQL。这一过程,并非像VC淘汰BC那么多盘外招,而是长时间争议与选择的结果。
对于信息操作规则定义,SQL几乎是最好的表达方式。接近自然语言,高度可读,并且非常利于优化。
打个比方,一个基于过程语言的上帝,这样说:
* 构造一个光源对象
* 构造一个能源对象
* 调用光源对象方法,设置能源
* 调用光源对象的发光方法,传入照明范围内的对象列表
基于SQL的上帝说,要有光。
当然,在这位老兄背后,要有打杂的小弟去完成插电点灯的事情,但是作为上帝,什么活都自己做了,要天使干什么?
看看那些应用层语言的list comprehensions(列表推导式)。不止一次我想要为Python实现一个基于存储层的列表推导式实现,都可耻的失败了。
当然,我承认这跟跟人能力有关,我不是Gudio。
看看LINQ,不管如何吹嘘,它就是一个抽象出I/O的SQL。我见过一些人激烈的贬低SQL,抬高ORM,同时又对LINQ顶礼膜拜,这可真够分裂的。
ORM对应用层编程效率的提升是客观的,无需回避。但是随着你数据操作越来越精细和复杂,就越来越需要通过规则定义来抽象High Order I/O过程。当你转了一圈儿回来,会发现自己又在写SQL。
想想Hibernate的HQL,想想C#的LINQ。
计算机不会变魔术。想让它做事更聪明,就需要你这个驭者更加聪明才行。
好的工具和方法可以给你带来更高的能力系数,但是记住,一个乘法计算,仅有一头大是不够的。
不懂SQL的人,是不能驾驭好ORM的。

与ORM做朋友

ORM对于开发工作,无疑是有好处的。我的朋友沈葳说,人脑能组织和分析的事务是有限的,所以代码越短,越有利于提高代码质量。从这个角度讲,ORM是非常重要的开发工具,其意义不亚于C API 函数集到GUI 框架的进步。
要想让ORM充分发挥威力,有时候需要从数据库设计时就做出一定妥协。
例如,你往往会需要加入自增标识列,会放弃一些精巧但是不利于ORM访问的依赖设定,甚至要放弃一些漂亮的命名(它们在应用层语言中是保留字,但是你用的ORM不懂如何规避)。
但是,这往往是必要的。就像建筑师向气候和建筑材料妥协一样。
在ORM默认的自增字段外,也许你还需要基于业务规则的唯一约束,那么额外加索引。
好的ORM会帮助你方便的查询数据字典,生成对象映射,跟踪数据变更,提供数据完整性的应用层检查,构造两阶段提交事务,减少不必要的I/O。
同样,不懂得运用ORM,也可能会破坏数据完整性,降低数据访问速度,甚至造成数据库死锁。作为项目开发人员,应该将ORM视为朋友而不是负担。

合理分层

过去,流行使用复杂的数据库设计,将业务规则存储于数据库的存储过程。现在,又流行抛弃数据层的一切约束,所有的规则都放在应用层。
这两者都不合理,除了应用需求的影响,前者与Oracle的广告部宣传有关,后者与MySQL阵营的鼓动有关。背后都有一些不合理的力量推动。
每一层应该保证自己的完整性,这才是分层的意义。那么,在数据库层,应该保证数据的完整性。
数据库备份出来,再恢复进去,应该可以得到所有的业务信息。
直接向数据库导入数据,应该可以有完整的数据规则保护。
数据库里保存的,不仅仅是表和记录,应该是完整的持久性信息。
从这个角度讲,配置文件和应用层代码中不应该有任何业务数据定义,这些信息都应该是数据字典表。如果出现了这种配置文件,大多数情况下都是愚蠢的错误。
实际上,包括Web网站常见的附件上传,都应该保存在数据库中。
独立的I/O文件存储、包括将外键约束转移到应用层,往往是因为对性能的妥协。以及,这里面确实存在MySQL阵营在推广过程中的一些不道德的宣传。
有效利用数据库功能,可以提高应用层的开发速度,简化代码结构,使得数据存储更安全。这通常仰赖与设计人员的经验,根据项目的具体需求进行调整。
基于这个原则,合理利用数据库功能,编写存储过程,触发器,调校索引,都是必要的。
我敢打赌,随着MySQL实现越来越多的功能,它的宣传材料上会越来越多的出现以前被MySQL所摒弃的复杂设计理念,并且宣称这是MySQL所独创或一贯倡导的。

收集整理常见的模式

在设计模式提出这么多年,在关系型数据库问世如此之久后,我很惊讶的一件事就是数据库设计模式仍然是一个相当冷门的领域。实际上,关系数据库的模式也有很多可循之规。例如用户信息(HR或CRM)、工作流,权限管理(如RBAC),订单等等,都有相当成熟的行业经验和时间,往往只要修改一些字段名,或者在关键架构的基础上加以扩展,就可以很好的用于实践。
每一个有志于成为高水平设计人员的开发者,都应该积极的收集自己体会到的数据库设计模式,积极的与同行交流。
这方面,Oracle的示例Schema,Postgres的示例数据库项目(在Soureforge上可以找到),都是很好的例子。相对来说,微软在MSSQL和Access中提供的示例库更为轻量和简单,也是作为入门的不错借鉴。

2009年4月26日星期日

啤酒鸭


这个其实超级好做,加上超市经常会有鸭子减价(例如珠海家乐福就时不时来个10元半只),实在是懒汉的好菜。



鸭半只
土豆若干
大葱葱白一段
大蒜瓣三瓣
花椒八角少许
啤酒两瓶

这锅半只鸭子我们两口子吃了两顿,单身汉过周末一般有这么多也差不多过一天了——如果你不吃饭,没别的菜,就鸭子和啤酒。
  • 土豆削皮切块备用
  • 鸭半只,切块,洗净下锅,净水焯一下,去掉浮沫捞出。
  • 锅里水倒出,放点油,下葱白,蒜瓣,花椒八角爆香。
  • 加入鸭块,倒啤酒一瓶。
  • 加入土豆,煮至鸭块熟透。
  • 加盐少许,这道菜只需要很少的盐。
  • 继续煮至土豆酥烂即可。
  • 中途观察,如果啤酒不够随时再倒一瓶进去。一般想要土豆煮够火候,一瓶不够。

备注:如果你喜欢稍清淡一点,啤酒味儿不那么浓的,可以只加一瓶,后面就续水。

2009年4月24日星期五

家常烤鸭

不追求全聚德水平的话,其实烤些鸭肉一家人吃并不难,简单的小烤箱也可以烤半只鸭了。我这里只有不到四分之一,所以看起来很小。
烤鸭真正麻烦的是烤前的准备,提前一天准备好鸭子,收拾干净以后用生抽、料酒、盐、桂皮、花椒、大料、桂叶等调料抹匀,反复按揉一段时间,为的是入味,肉质也会比较松软。然后保鲜膜包好放进冰箱,12小时以后拿出来,才差不多入味。然后可以看自己喜好要不要涂一层蜂蜜。烤箱200度预热好,烤一小时。或者像我这次这样,鸭肉比较小块,就自己估计要不要提前出炉。
香料不一定百分百按前述来,但是强烈推荐桂叶和八角,很香。
喜欢北京风味,可以提前涂上蜂蜜,风干。网上介绍北京风味脆皮烤鸭的文章有不少,就不献丑了。
可以配啤酒,也可以配烙饼,都是不错的搭配。

2009年4月20日星期一

砂锅鱼块

在太太的努力下,家里终于开始像个家样了。在亲爱的老婆大人布置的厨房里,连我都想做饭了!


其实这东西煮起来很简单,嘿嘿。最下面铺白菜块,要大块一些,然后是鱼块,然后是豆腐,码齐以后加水,煮到九成熟加盐,出锅时调一点胡椒,很方便吧:)。

2009年4月7日星期二

Why Postgres?

关于这个话题,我想了很久,反复开了几个头都不太满意。看来还是直接了当比较好。
我并不是只使用过Postgres的用户。正相反,从MSSQL到Firebird再到Oracle和MySQL,加上LDAP等,我在工作中用过的至少有八九种数据库产品。但是,Postgres是我至今遇到的最满意的数据库平台。
首先,Postgres足以可靠的支持我所要管理的数据量。历经二十多年发展的Postgres一直是主流数据库服务系统的代表之一。长期大量用户的使用,已经证明了它在TB级应用的可靠性和可用性,这足以满足我的需求。早在上个世纪,Postgres就与DB2和Oracle等昂贵的商业平台一样,支持多层存储管理,从文件系统到表空间再到数据区集群。通过完备严谨的分层定义,为海量数据管理提供了可能。
能够提供这一级别的数据存储能力的数据库不在少数,但是Postgres除了这一基本能力,还拥有一些独到的特长。
Postgres以完备和高度可靠的事务见长。这在一个严肃的商用系统中是非常重要的指标。正因为如此,传统的几大数据库巨头对此都非常重视。然而Postgres作为伯克利分校出身的开源产品,一直在数据库事务技术的发展中处于领导地位,这是一项非常了不起的成就,也是商业应用的有力保障。
Postgres与*nix有良好的集成,几乎每一个linux/unix/bsd发行版,都将Postgres的支持和集成作为重要内容。从Postgres 7.x 版本至今,Postgres对于windows支持也越来越出色。现在的Postgres For Windows 版甚至还附带了一个集成配置安装工具。对于高性能及高可靠性应用场合,能否允许灵活的选择适合的系统组合,还是很重要的。
Postgres 在少量连接数的情况下,性能测试并不出色,只能说中规中矩。然而高并发高负载的严苛环境,Postgres 的测试结果远超MySQL等竞争对手。

以下链接可以看到FreeBSD7.x上,Postgres对MySQL表现出的强大性能优势:

以下链接可见Postgres在高并发应用中表现出的优势。

这种高并发优势,无论web广域应用,还是企业应用,都至关重要。强大的并发支持,可以允许架构设计人员在应用层架构选型时有更多的机动余地。

除了以上几点,Postgres的编程能力,更是远超群雄。Postgres曾经在近十年间都以SQL语言的竞争者身份出现,然而这不等于它在SQL编程能力方面有所缺失。恰恰相反,Postgres拥有当下语法最丰富好用的SQL/PLSQL脚本引擎。Postgres独到的实现了函数与过程的统一定义和使用,并且做到了标量函数与矢量集函数的灵活组合。无论触发器、主外键关联、视图、唯一索引,各种关系约束一应俱全。
Postgres 实现了相当完备的面向对象支持。一直以来,Postgres都是对象-关系型数据库的技术先锋。灵活的类型设计,加上完备的关系机制,使得 Postgres 成为最方便实现设计思想的数据库之一。
除了传统上的C扩展存储过程,各主流数据库还纷纷支持各种应用开发语言,例如,Oracle支持java(通常都是过时版本),MSSQL支持.net  CLR,但是,早在这股风潮之前,Postgres就已经支持高达十余种不同的编程语言。得益于开源社区的贡献,Postgres支持Java、Python、Perl甚至Scheme、sh等编程语言,而这个列表还在增加。而且这些功能都是单独安装的,使用系统集成的适用版本,项目设计人员和架构师可以方便的选择最适合的组合。
Postgres还有大量类似的“插件”可供技术人员选择,包括数据库集群、服务器同步、全文索引(已有完整的中文支持)等等。大部分扩展功能,都可以通过简单的安装步骤直接使用。
这些强大的功能,足以使得Postgres服务器成为一个强大的数据管理和挖掘平台,或者一个功能丰富的业务开发平台。无论对与开发人员、维护人员、项目设计人员,还是最终用户,Postgres
总能提供更方便、强大和可靠的支持。

2009年3月5日星期四

[坑]启动一个时间管理项目,广告一下

现在我用的时间帐单工具,昨晚正式开放出源码。

大概google大神被我的若干僵尸项目激怒,昨晚code.google又神奇的不能开项目了。于是我找了一个支持mercurial工具的网站。

项目地址如下:
http://bitbucket.org/March/astinus/overview/

有兴趣的同学可以注册一个帐号,发给我,我加你进项目组。该网站支持openid(www.openid.net),我就是用自己的blogger地址(blogger是openid成员之一)注册的。

背景:
Astinus(阿斯特纽斯),龙枪编年史中的大图书馆馆长,克莱恩编年史的作者。他永远都在不停的书写编年史,记录克莱恩世界所发生的一切。他是永生不死之人,是第一个踏上克莱恩之人,最后一个离开克莱恩之人。传说他是中立之神吉利安的化身,但从来没有得到过证实。

目标平台:
客户端:web浏览器,或web service客户端
服务器:Linux,我希望可以扩展到FreeBSD,前提是只要nlpbamboo支持。以目前的情况看,无法保证windows服务器环境的可用性,但是我欢迎有进行windows移植的人,理论上讲只需要解决nlpbamboo的移植。
数据库:Postgres
应用层:web.py

开发环境准备:
操作系统:linux(如前,欢迎Windows尝试,非常渴望FreeBSD支持)
版本管理工具:mercurial
数据库:Posgres 8.3.x +
应用服务器:web.py
浏览器:欢迎任何常见浏览器用户的参与,精力所限,我本人只关注Firefox 3。
第三方开发包:nlpbamboo(http://code.google.com/p/nlpbamboo),jquery,以及其它可能存在的相关组件。

本项目欢迎(非必须,欢迎任何有兴趣的朋友参与):
文档高手,特别是擅长组织文档及编写使用指南的人士。
翻译专家,需要有意帮我中译英的好人。
网页开发人员,本项目使用JQuery,对CSS和Ajax的需求不言而喻。
熟悉web.py的程序员。
我关注该项目与Trac的互联能力,欢迎trac开发高手。
欢迎有意为这个项目开发各种异构客户端的人。
数据统计与分析,特别是自然语言分析方面的人士。
Postgres程序员,非常欢迎能比我更擅长写SQL脚本的人士。
或许,我们还需要FreeBSD上的C++程序员,目前nlpbamboo项目的开发人员不保证该工具在BSD上的可用性。

2009年3月1日星期日

[Postgres] 近期关注

授权与授权的管理
数据库版本升级时的数据保护(manual 24.5)
数据库同步与复制(manual 25)
数据库自动优化autovcuum(manual 18.9&23.1.4)