2009年11月22日星期日

数据库技术人员的能力评估建议与培养规划

数据库技术人员的能力评估建议与培养规划

http://zerolab.co.cc/?q=node/41

  • 自挖坑,存档

岗位职能区分

数据库技术在现代软件技术领域有广泛的应用,与数据相关的技术岗位和职能,也可以区分为若干个不同的类别。根据在一个理想的开发团队中不同的分工和知识掌握的不同,可以区分为:

  • 程序员
  • 分析师
  • 设计师
  • 架构师管理员

对于数据库领域,分析与设计岗位、架构与运维岗位(管理员)的重叠较高。特别是分析与设计岗位通常在团队中由同一(组)人承担。在更多的团队中架构师也与分析和设计人员的岗位重叠。因此,从项目开发周期考虑,可以简单的分为三类:

  • 分析与设计岗位(含架构)
  • 开发岗位
  • 运维岗位

个人能力发展路线

基本路线图

  • 初级程序员
  • 中级技术岗位
  • 初级设计人员
  • 初级管理员
  • 中级开发人员
  • 高级技术岗位
  • 架构师
  • 设计师
  • 高级管理员

入门

常来说,新手接触数据库技术,从程序员岗位做起。这是因为对于数据库技术,此岗位比较容易切入。在软件开发团队中,通常允许初学数据库技术的开发人员,从

事受限的数据库开发工作,此类工作内容可以是基本的增删改查,其数据结构已经由设计人员固定。初级程序员岗位是练习 SQL

语言基本技能、理解关系模型的很好的切入点。

近 年来,此岗位工作通常使用 ORM

工具来完成工作,以提高工作效率和质量。但是对数据库的了解仍然对这个岗位有重要意义。对数据库知识有深入了解的开发人员,可以编写出更高质量的

ORM 代码,可以在必要的时候越过 ORM 的功能局限,编写扩展代码,可以定位性能瓶颈进行优化,等等。

此,关系型数据库研发岗位,在当今应用层封装技术非常成熟的前提下,入门更为容易。程序员可以先从 ORM

入手,通常自己比较熟悉的应用层编程环境学习数据访问知识,然后再进一步了解 SQL 语言的知识。另一方面, ORM

并不能代替关系数据库本身。关系数据库知识的掌握程度直接影响程序员的职业发展。

提升

分析/设计岗位

术人员掌握了基本的数据库访问知识后,通常在数据库技术领域,可以有三个不同的发展方向。常见的一个发展方向是转入分析与设计领域。UML

的用例分析、类图、需求分析等知识,与关系数据库的基本设计工具 E-R

图有直接的关系。由此也可以看出,关系数据库的设计和分析工作其实是整合在项目开发过程中的。因为,向此方向发展的技术人员应该提升综合能力,转向软件分

析设计知识。

良好的项目分析准备,能更好的厘清数据库设计所需要的信息。良好的数据库设计,是编写出优质应用层代码的基础。个人前期工作中积累的数据库编程经验,能够使得设计师理解数据库设计中的关键点,了解基本泛式和常见设计模式的运用方法。

===== 中级开发人员 ====

面向数据库的编程工作,本身存在较深入的技术要求。高水平的数据库开发人员,面对各种问题,可以更快的给出解决方案,提供高质量的软件产品。

通常在复杂查询、复杂事务、数据迁移、业务报表定制等方面,需要高水平的开发人员支持。

初级管理员

初级数据库管理员可能由开发人员转岗,也可能独立学习,或由系统管理员转岗。除了掌握系统管理员的基本能力,还要了解关系数据的知识。

作为数据库管理员,要能够实现数据库服务的部署、备份、恢复。能够为开发人员和客户提供问题诊断、预警支持。能够找出运营过程中发生的常见问题,予以解决。

高级技术岗位

架构师

对于大型项目,系统架构成为独立的、重要的岗位。架构师要求综合性的知识和能力,有关数据库领域,主要在于集群设计,备份方案的实现,这需要对操作系统、网络工程、数据库自身的特性都有深入的了解。要求能够解决项目中数据库层的性能和可靠性问题。

设计师

通常来说设计师的工作与架构师有一定的重叠。相对来说设计师的工作更偏"软",需要与开发团队有更多的交流。往往设计师要肩负高级数据库开发人员的职责。同时要有对业务的深入了解。能够设计出应对海量数据、高可靠性、复杂业务的数据库方案。

高级管理员

高级数据库管理员是通常概念中数据库领域的高端岗位。这个岗位要求有很强的运维技术能力。要能够参与数据库架构方案的设计,并将其实现。要求能够完成复杂集群的实施、备份恢复方案实现、预警和问题诊断。

技术能力评佑

初级岗位

预备要求

  • - 掌握基本的编程知识,能够用项目使用的编程语言参与开发
  • 文档阅读能力,能够读懂项目文档,使用术语与团队成员交流
  • 有内外存的基本知识

达标指标

  • 能够使用 ORM 工具(对我部门建议 SQLAlchemy )进行基本的增删改查操作
  • 能够理解 ORM 生成的 SQL 脚本
  • 能够手工编写简单的单表和两表关联操作
  • 学会使用客户端工具

中级岗位

中级开发人员

  • 能够使用 SQL 语言解决复杂的查询
  • 熟练使用工作数据库平台,包括特定的编程功能
  • 熟练使用 ORM 工具,可以灵活的使用 ORM 和 SQL 解决工作中的技术问题
  • 可以判断出程序运行中的数据性能问题、设计问题,提出解决方案

分析/设计人员

  • 能够理解业务模型,将其转化为数据模型
  • 能够使用 UML 完成从需求分析到数据库设计的思考和工具
  • 能够设计出合理的数据库结构,编程方便,维护容易,避免性能和安全隐患
  • 能够指导初级开发人员解决技术问题 - 熟练阅读和编写复杂的 SQL 语句

管理员

  • 熟悉 SQL 编程,能够编写复杂的报表查询和数据操作 - 熟悉 *nix 系统环境能够
  • 了解数据库安装和部署方法 - 能够为架构师和开发人员提供问题诊断支持
  • 能够设计和实现基本的备份方案 - 能够使用系统脚本和 SQL 快速解决常见的管理问题包括:
  • 数据备份恢复
  • 服务器状态查询
  • 解决死锁、死链
  • 存储迁移
  • 授权管理

高级岗位

架构师

  • 熟悉特定数据库的特性
  • 能够理解需求分析,掌握客户需求
  • 能够设计出合理的服务架构和运维方案
  • 能够为开发和设计人员提供数据库技术的咨询支持
  • 能够为运维人员提供数据库运维问题的解决方案
  • 能够为客户提供良好的售前咨询

设计师

  • 熟悉项目设计
  • 了解业务需求,能够与分析人员和客户进行良好的沟通
  • 了解数据特性,能够根据使用的技术进行设计
  • 能够将业务需求转化为良好的设计方案
  • 能够为开发和设计人员提供数据库技术的咨询支持

管理员

  • 熟悉机房环境
  • 熟悉操作系统和服务器的运维技术
  • 熟悉数据库特性
  • 能够制定数据库服务器整体运维方案
  • 能够为数据库运营提供灾备、预警、优化、扩展服务


--
每一个成功都是不可复制的。
……

劉鑫
March.Liu

2009年10月7日星期三

Bitmap 的数据库持久化实现

以下是基于数据覆盖的一个初步讨论,实用中,位映射有广泛的应用领域,也有大量的算法实现需求。在经过初步的推演后,我发现这不是可以一蹴而就的。所以先给出一个简单的实现和应用算法讨论。

Bitmap 的数据库持久化实现

Bitmap 是一个常见的数据类型,常用于优化大量数值的存储和查询。这个概念对于数据 库程序员应该不陌生,Oracle 等数据库通过这种技术优化查询。通常程序员会在一些算法 或数据结构书籍上读到以 C 语言 char* 实现的 bitmap 。这里,我们考虑一个在数据库中 存储的 bitmap 实现。

PG 上的数据结构实现

bitmap 的实现不难,PostgreSQL 中提供了 bitstring 类型,可以直接存储位串。但是单行 bitstring 能提供的数据长度终归有限。为了存储和性能的需要,我们将其设计为一个表。 通过索引值将 bitmap 分片为 bitstring 集。

create table bitmap(idx bigint, segment bit(32));

分析

计算时我们将一个bitmap表视为一个完整的bitmap数据集,设 segment 的宽度为 w ,索引 值为 i 。将第行的 idx 置为0,则第 i 个索引行上的第 b 位对应整个 bitmap 的第 b+i*w 位。逆推之,bitmap 第 x 位为 x div w 行,第 x%w 位。

因为数据分行存储,位计算操作也需要重新定义,要考虑跨界定位问题。Postgres 的 bit 本身支持左移右移操作。这点并不复杂。可以利用掩码技巧将计算参数分解为区片。具体算 法几乎与 C 语言版本一致。当然针对一些有规则操作时,可以充分的利用 SQL 和 PLSQL 的语法特色进行简化。

实例

覆盖统计

详细内容介绍见下一段中的链接。这里简单介绍一下:每个数据样本是一个由大量一维区间 值组成的文本。每一行是一个(起点,终点)区间。要计算二到N个样本件的覆盖率。而数 据本身是未经整理的,可能有重复。

事实上,这个例子是我最初着手实现 bitmap 的起因。可以说 bitmap 可以直接优化此类问 题,首先bitmap以至少8倍以上的比例节省存储空间(以 c 语言 char* 每字节存储位置状 态来计)。而空间缩减后对查询性能也有直接提升。

这个应用的操作非常好实现,将收集来的数据区间段(s, e)转换为二进制数 2^s+2^(s+1)+...+2^e ,即从 s 到 e 之间都为1的二进制位串。然后与整个 bitmap 做或 运算。示例代码如下:

create or replace function segment_over(s bigint, e bigint) returns void as $$
declare
sidx bigint;
eidx bigint;
d_data bit(32) := 4294967295::bit(32); -- pow(2, 32) -1
begin
if currval('bitmap_idx_seq') < (e/32)+1 then
for i in currval('bitmap_idx_seq')..e/32+1 loop
insert into bitmap(segment) select 0::bit(32);
end loop;
end if;
sidx := s/32;
eidx := e/32;
if sidx = eidx then
update bitmap set segment = (d_data << cast((32-e%32) as int))&(d_data >> cast((s%32) as int)) where idx = sidx;
else
update bitmap set segment = segment | (d_data >> cast((s%32) as int)) where idx = sidx;
update bitmap set segment = d_data where sidx < idx and idx < eidx;
update bitmap set segment = segment | (d_data << cast((e%32) AS INT)) where idx = eidx;
end if;
end;
$$ language plpgsql;
优化分析

此示例中,segment_over 操作并未做任何深度优化,仅仅是将前述的思路直接实现出来而 已。实际上根据业务,我们还可以进一步的提高操作效率。

例如,由于覆盖度操作是在数据区迭加或操作,单向的填充动作,可以将已覆盖区间直接压 缩掉(这需要将 idx 字段扩展为起点和终点一对数据,或者通过触发器机制同步一个查询 表)。

再例如,前例中我们的 segment 长度为32,idx 是一个 bigint 类型。这对于海量数据比 较有效,不过如果总样本量较小,完全可以用 integer ,这样可以减少很多转型操作。

在 segment_over 中,我写了一个防出错的探测代码,如果索引值超出了初始化范围,会扩 展 bitmap 表。但是实际上很多应用,其总数据量是有明确上界的。此时可以去掉这部分代 码,使用一个一次性的初始化代码,例如下面这样:

create or replace function init(len bigint) returns void as $$
declare
i bigint;
begin
truncate table bitmap restart identity;
insert into bitmap(idx, segment) select 0, 0::bit(32);
if len/32 < 1 then
return;
end if;
for i in 1..len/32 loop
insert into bitmap(segment) select 0::bit(32);
end loop;
if len%32 > 0 then
insert into bitmap(segment) select 0::bit(32);
end if;
end;
$$ language plpgsql;

将 segment 的宽度调整为略大于覆盖区间长度期望值的数值,可以减少对中间区间的覆盖 操作,也有优化读写效率的可能。

数据库实现的动机

使用数据库存储 bitmap ,可以避免海量长度 bitmap 超出内存容量的情况,是一个比较经 济的实现方式,特别是在机器不够强劲,或者没有条件部署云或网格集群的场景。只要熟练 数据库层开发即可。

由于 Postgres 中已经实现了完备的并发访问、数据备份和查询等功能,可以避免自己开发 文件型 bitmap 所需要考虑以上问题,带来的开发成本。轻松可以满足 OLAP 的需求,在线 随时查询覆盖情况。

合理的使用数据库功能,可以有效的降低使用和开发成本,这种组件式的开发和集成方式, 对于当下追求灵活、高性价比和可持续性的 IT 产业理念,是契合的。


……

劉鑫
March.Liu

2009年9月24日星期四

sqlalchemy、storm和web2py dal的比较报告

工作项目报告,所以抹掉项目名先,以"X"代之。

分割线内内容仅代表个人意见,与所供职企业及参与社区无关。

===================================

X 从很早的时候就出现各种数据库访问错误。包括链接数占用过多,死锁,
僵尸事务等。本周我集中梳理了一遍代码。我认为,虽然数据库设计方面有诸多
不合理之处,但是这些不合理主要影响业务错误,造成 X 性能和使用上的
问题是因为使用的ORM框架 storm 有严重的缺陷。

首先,storm 对数据库架构的同步有非常奇怪的设定。它不自动同步表结构,却插
手外键关联关系。强制要求外键必须都是级联更新、级联删除、set null。且不说
其设定中有自相矛盾之处,本身在MIS系统中做级联删除就是一件很危险的事——除
了系统维护、分表,MIS系统不应该删除任何数据。 storm 从一开始设计恐怕就没
有考虑企业级应用,但是对于web 开放式应用,storm 对外键的依赖又太笨重了。

其次,storm 在联接数据库后应该会有 DDL 操作(即修改数据库结构)或独占锁
定事务,此推断的证据在于用 storm 联接到 S 库后, S 无法进行
vacuumdb -a -f 处理。而根据 Postgres 手册,PG只有在遇到有链接正在进行
DDL 操作时,才会产生库级锁,造成 vacuum 操作无法进行(或手工建立一个隔离
级别相当的事务锁定)。作为世界上并发能力最强的数据库产品,正常的数据访问
操作与 vacuum 根本不会冲突,热处理资源回收正是 PG 独到的特性。这样造成了
X 应用频繁用光所有的链接数,还在数据库服务器遗留僵尸进程。我观察到
有僵死十几二十天没有完成过的 X 链接,这应该是因为同时多个 storm 链
接提交错误的锁定关系,造成死锁。

第三,storm 如果可以象 DAL 那样,明确设定不同步数据库,以上问题至少可以
解决一半,但是它没有链接配置参数。这造成了我们对其出现的问题无法进行友好
的调整。现在同事在 X 的 controll 层添加了强制的 commit 操作,一定
程度上减少了死链,但是我仍然观察到有点击 X 页面(在测试环境下)无
法响应,甚至造成数据库服务器闪断重启的现象,对于同时运营三十几个数据库的
数据库服务器,这是非常大的安全隐患。

昨天我尝试将 X 的数据库访问层迁移至 web2py DAL,经过一天尝试,总结
出以下的问题:

第一,DAL 缺少精确实数计算类型,它不支持 Numeric 或 Decimal,只能用
double,这是一个相当大的安全隐患,对于涉及财会计算的应用,使用浮点数是一
种很不严肃的作法。

第二,DAL 不支持数组和大数据类型,此类字段在 X 中有几处应用。

第三,DAL 对原生SQL的支持比较初级,虽然也可以使用,但是有时需要兼顾开发
速度,希望可以组合使用的时候,就会受限。

以上问题不是不能解决,但是需要修改 DAL 本身。虽然我一直有计划改造 DAL,
fork 一个对 PG 有良好支持的分支出来。但是这显然需要更多的开发时间。

昨天我详细查阅了一下 sqlalchemy 的文档,进行了一些简单的尝试,感觉这个
ORM 框架比较符合我们的需求:

第一,sqlachemy 对数据库链接的隔离级别和事务有良好的控制,默认也不会去尝
试DDL操作。

第二,sqlachemy 有非常丰富的数据类型支持,包括BLOB,Decimal/Numeric,以
及为 PG 特别定制的数组类型。

第三,sqlachemy 的查询类似 DAL (很可能DAL学习自sqlachemy),对各种查询操
作有良好的支持,还可以嵌入 SQL 片段,也可以方便的直接传入 SQL。

第四,sqlachemy 其实并不难学,它的功能虽然丰富,但是只掌握自己要用到的部
分即可,不需要完全学会,上手还是很简单的。

第五,文档比 storm 完整的多,而且现在仍在活跃开发。

第六,数据存储模型与业务模型分离,虽然看起来有重复劳动,但是对于一个需要
长期维护的企业应用项目,这是正确和严肃的作法。

第七,对特定数据库的特性有良好的支持,还可以扩展。

在使用 sqlachemy 时,我们还可以结合 web2py 原有的一些优秀工具,例如广泛
用于 DAL 的storage类型,这是一个类似 JS Object 的智能对象类型,很适合动
态结构的数据对象。

对于 X 项目的数据访问层重构,我评估工作量至少在一周左右。如果全部
换用 sqlachemy ,可以一劳永逸的解决数据库访问的问题,甚至 S 的后续版
本,我也建议尝试使用这个框架,毕竟这比 hack dal 要方便一些。

sqlachemy 当前的稳定版本是 0.5.6 ,我昨晚试验了开发中的 0.6 ,发现功能还
没有完整实现,现在还不能实用。


===================================

--
光见贼吃肉,没见贼挨打。
……

劉鑫
March.Liu

2009年9月15日星期二

近日 twitter 发布信息整理

  
   数据库的架构与设计,应该从整体的范围去看问题,要从"数据存储和管理服务"的角度,而不是"数据库软件"

   应用层开发阶段,可以不加入外键,在数据库运营阶段,由DBA补完

   ID列的主键身份,其实只是为了与ORM妥协,在很多情况下,一个表只有ID主键列,既危险又愚蠢。如果应用层存在BUG,就会引发严重问题。我的建议是,至少在运营前期,就为关键实体数据加上唯一索引。

   存储过程有没有用?这个要看情况。做数据库架构就像建筑工程,不是"对""不对"这么简单。早年Oracle宣传一切逻辑都封装在存储过程中,数只从存储过程访问,这叫蛋疼。后来MySQL宣传外键存储过程触发器都不需要,只要能增删改查,这叫犯二。

   一个数据库要如何设计,业务对数据可靠性、完整性、性能的需求平衡是一个很重要的因素。对于用户访问日志(包括点击率等等),有一定的误差也是允许的,而商务活动往往是不允许有哪怕毫厘之差。针对不同的业务,应该有不同的设计和架构方案。
         
   上次李元佳先生介绍的EDB集群方案给我一定启发。典型的集群节点可以每节点由三个机器组成:一个查询节点,一个写入节点,一个备份节点。写入节点和备份节点多出来的内存可以共享给查询节点做为无限缓存(EDB特有功能)。
         
   有时查询节点还要负担起OLAP的任务,或者本身统计查询的计算量就远大于写入量,此时可以由一个写入节点带多个查询节点,或者直接向一个EDB网格同步。当然网格化以后,写入性能通常会有接近线性提升,这样可能就不需要写入节点了。

   前段时间我写过一篇文章,合理利用触发器,可以把一个无限增长的日志表访问,变成限定于20条数据的访问,如果按现在流行的MySQL+ORM,这种东西是做不出来的。
         
   事实上很多项目,尤其是高负载的互联网应用,最终都没有使用ORM。既然如此,拒绝数据库服务端编程就是一件很奇怪的事。在数据库服务端进行合理的编程,可以大大提高性能。
         
   既然数据库服务是作为一个整体使用的,那么性能分析也要从整体考虑。有些功能虽然单独比较性能不高,但是却能在合适的时候,提高应用的整体性能。
         
   数据库设计要符合业务,不要拿来作为自己炫技的场所。
         
   虽然这年头是个人都知道出来吼一句"数据库太慢!"以显示自己牛B,但实际上有多少是真的牛B到跨过了关系型数据库的极限,有多少只是不懂数据库在那里装B呢?
         
   观点:DBA的职责,除了维护工作,应该有以下几个——帮助设计人员找出性能和安全方面的问题;帮助开发人员解决数据库方面的问题,例如一些用其它手段难以解决的性能瓶颈和复杂逻辑;协助架构师制定系统持久层架构;为乙方(通常是DBA就职的一方)提供架构方面的专业意见。
         
    个人认为大多数应用不应该出现大量存储过程,尤其在ORM比较成熟的现今,基本不需要为CRUD操作封装存储过程,而存储过程不能与用户多步交互执行,这就决定了它不会主导事务处理逻辑。但是存储过程可以简化复杂的事务逻辑。
         
    简单的说,存储过程最好是在开发由粗到精的优化过程中加入,代替需要优化的代码部分。如果是那种希望快速粗放的拼装一个项目然后交钥匙不管的初等级开发(不要拿这个来冒充XP过程)并不适合过多使用存储过程,最好是用熟ORM,积累并复用确实有效的一些存储过程和SQL脚本模板。


--
话题越大,废话越多;名字越火星,问题越脑残。
……

劉鑫
March.Liu

2009年8月31日星期一

[Postgres Story]最近访问用户问题

前几天有个朋友提了一个问题:

应用平台需要统计最近访问的20个用户的信息。

我第一个想到的是用memcache之类的专用的缓冲,以用户名为键,以最后访问时间为值,如 果用户访问比较均匀,限定一个合适的 超时值,查询的时候遍历过滤就好了,虽然不是很 精确,但是实现起来够简单。

答:不可以,领导要求只在数据库端解决。

环境准备

提问的朋友使用的是 MySQL ,这里我用一个 PostgreSQL 8.4(Enterprise DB Postgres Plus Stand Server 8.4) 建立实验环境。操作系统是 Windows 7 RC。

客户端是 Emacs sql-postgres,\timing on。

使用 explain analyze 分析性能消耗。

尝试

那么,最简单的应该是在日志表上查询:

select username, max(logintime)
from log
group by username
order by 2 desc
limit 20;

这里假定的是会话表(log)中有名为 username 的用户标识列,名为 logintime 的时间戳字 段。

但是显然这个查询的性能并不好,它要遍历整个日志表。

首先,我们给日志表加一个聚集索引,使它按插入时间倒排(显然这对插入效率不利)。

create index idx_logintime on login_session(logintime desc);

alter table login_session cluster on idx_logintime;

然后,再进行查询,可见效率有微弱提升。在我本机的 Postgres 8.4 上,通过 explain analyze 可见有不到百分之二的效率上升。我甚至怀疑这仅仅是源自一些随机事件的影响。

换一个角度分析,只要 select max ... group by ... 的模式不改变,就很难有根本的性 能提升,最好的办法仍然是缓存。

改进

有个简单的办法,可以在PG数据库中制造一个缓存表:

  • 首先,直接建立一个 user->timstamp 键值对表。如果用户量不大,可以直接这样:
  create table sessions(username text, seqs serial, logintime timestamp, primary key(username));
  • 然后创建一个触发器函数
create or replace function on_log() returns trigger as $$
begin
if exists(select * from sessions where username=NEW.username) then
update sessions set seqs = nextval('sessions_seqs_seq') where username=NEW.username;
else
insert into sessions(username, logintime) select NEW.username, NEW.logintime;
end if;
if (select count(*) from sessions)> 20 then
delete from sessions where seqs < (select min(seqs) from (select seqs from
sessions order by seqs desc limit 20) as t);
end if;
return NEW;
end;
$$ language plpgsql;

create trigger onlog after insert on log for each row execute procedure on_log();

OK,这样一来,经过反复测试,在我的笔记本上,插入速度基本没有降低(约 2%~ 5%), 而查询"最新的20个用户"这一操作,速度提升了一百七十余倍。几乎可以视作是一个数据库 端的队列缓存了。这个数值是基于 log 表中有五万条数据,在实际应用中日志表十万以上 (按每日切分导出)比比皆是,性能差距会更为显著。

分析

"最新的 20 个用户",这一问题,与"最近5分钟内的用户"此类问题的区别在于,它不能通 过获取当前时间,简单回溯得到有效数据区间。如何避免遍历整个日志表是一个关键问题———— 现代的在线服务系统每日访问日志量动辄数十万,几百上千万的也不罕见,第一种解法明显 不能满足。相比之下,第二种方案不需要干涉日志表的存储排序,不需要建立多余的索引。 通常我们讲触发器速度比较慢,但具体到这里,只是却是一个比较快速高效的实现方案。

如果用户量不大,在几千以内,为用户表建立一个最后登录时间字段,绑定 null last 索 引(可以加上FASTUPDATE=ON),然后利用基本的order by limit就可以得到比较慢意的效 果了。但是对于大型SNS等应用,数十上百万用户也是有可能的(甚至大型企业内部应用, 数万乃至上十万用户的系统也不在少数)。此时,第二种解决方案就理想的多。虽然看起来 在session表上反复进行计算和写入,但是由于session表的数据量非常小,永远只有几十 条,所以计算速度很快。如果对 log 表进行恰当的分区,同时将sessions表存储到另一个 区域(甚至直接缓存到内存),那么对于海量数据,也会有一个稳定的,良好的性能表现。

更进一步的解决方法,则应该是在数据库或应用层服务器环境,建立一个内存中的队列,来 记录这个数据。只要注意并发写入的问题,就可以得到很好的性能。这方面Haskell的STM机 制、我之前用在MSG.Summoner.Trac的旋转锁机制、都可以比较漂亮的解决这一问题。

优化

sessions 表的读写都非常频繁,通常有比较多的 update,,但是数据量基本恒定。应该积极的执行 vacuum。

可以为日志表添加一个 uuid 字段,以便在数据量上升时按 hash 分表。这样可以获得更好 的写入性能。

可以将 session 的主键索引设为 FASTUPDATE=ON 。

触发器中设定

SET LOCAL synchronous_commit TO OFF;

打开 WAL 异步事务提交,可以进一步提高并发写入速度。

更进一步的,可以写一个常驻的守护进程,用应用语言建立一个队列,将这一需求建立为独 立的服务。这个服务可以通过 pl 嵌入语言与数据库联接,也可以直接联接到应用层,有一 些应用层架构依赖于并发的多 fastcgi 实例,此时要注意并发访问冲突和数据同步的问题。

总结

之所以出现这样一个困扰开发人员的问题,根本在于项目领导不提供,也不认同使用灵活、 开放的思维方式解决此问题。服务项目的架构是一个系统工程,类似这样的问题,完全可以 用更开阔的眼光去寻找出路。建立一个简单的缓存队列实例,用perl或python,只需要数十 行。结合Postgres的plperl或plpython等嵌入脚本,可以非常简单的达到目的。甚至不用担 心使用多实例 fastcgi 时,多个应用服务进程争用缓存队列I/O的问题。

即使从方案二出发,通过利用服务器环境的资源,也可以做出更多优化。如把"删除第20之 后的旧数据"这部分脚本,移到 crontab 中,与vacuum 结合执行。会得到更好的效率。

找我请教的这位朋友,使用的不是Postgres,而是MySQL,相对来说很多PG的服务端编程技 巧难以照搬,再加上团队管理的政治问题,我也只有祝他好运了。



--
话题越大,废话越多;名字越火星,问题越脑残。
……

劉鑫
March.Liu

2009年7月24日星期五

Emacs 窗体的透明设置

昨天朋友发来一个代码给我,可以让 windows 上的 emacs 窗体像 X 或苹果那样实现半透 明。代码并不复杂:

(set-frame-parameter (selected-frame) 'alpha (list 85 50))
(add-to-list 'default-frame-alist (cons 'alpha (list 85 50)))

然后经过一番努力,我写了一个切换功能,按f7进入透明,按f8退出透明状态。

(defun transform-window (a ab)
(set-frame-parameter (selected-frame) 'alpha (list a ab))
(add-to-list 'default-frame-alist (cons 'alpha (list a ab)))
)

(global-set-key [(f7)] (lambda()
(interactive)
(transform-window 85 55)))

(global-set-key [(f8)] (lambda()
(interactive)
(transform-window 100 100)))

但是这种东西两键切换显然不够友好,于是我把它改成了一键切换。

(setq is-alpha nil)

(defun transform-window (a ab)
(set-frame-parameter (selected-frame) 'alpha (list a ab))
(add-to-list 'default-frame-alist (cons 'alpha (list a ab)))
)


(global-set-key [(f8)] (lambda()
(interactive)
(if is-alpha
(transform-window 100 100)
(transform-window 85 50))
(setq is-alpha (not is-alpha))))

后来复读了一下代码,觉得还有改进的余地。首先,只是一个透明度切换,没必要占用两个 快捷键,对于我这种用 Emacs 写 N 种东西的人,快捷键是种相当宝贵的资源。再一点,目 前的设计只能支持两种透明度,还多用了一个全局变量。

在 Feather 兄弟的指点下,我突击了一下 emacs lisp ,写出了这样的版本:

;; transform window
;; Anchor: March Liu (刘鑫) <march.liu@gmail.com>
;;
;; This is a script to set emacs window's alpha value.
;; It work well on windows xp and vista with EmacsWin32
;; useage: add below line in your .emacs
;;
;; (load-file "path/alpha-window.el")
;;
;; you can define your alpha-list to set the transform combine
;; bind key with below code:
;;
;; (global-set-key [(f11)] 'loop-alpha)

(setq alpha-list '((100 100) (95 65) (85 55) (75 45) (65 35)))

(defun loop-alpha ()
(interactive)
(let ((h (car alpha-list))) ;; head value will set to
((lambda (a ab)
(set-frame-parameter (selected-frame) 'alpha (list a ab))
(add-to-list 'default-frame-alist (cons 'alpha (list a ab)))
) (car h) (car (cdr h)))
(setq alpha-list (cdr (append alpha-list (list h))))
)
)

这个脚本的特点如下:

  • 单命令轮转任意多个状态
  • 可以用 (global-set-key [(f11)] 'loop-alpha) 把 loop-alpha 绑定到快捷键上
  • 我设定了四个透明度组合,你可以在自己的 .emacs 里重定义 alpha-list ,设定自己 的透明度方案

目前我只在windows上试验过了,X窗口下如果没有开透明效果应该是不行的。当然,X本身 的半透明就很好用了,我在X上从来没想过需要这么个功能==;

应该只能用于图形界面:P。



--
话题越大,废话越多;名字越火星,问题越脑残。
……

劉鑫
March.Liu

2009年7月23日星期四

Postgres 8.4 的更新内容概要

After many years of development, PostgreSQL has become feature-complete in many areas. This release shows a targeted approach to adding features (e.g., authentication, monitoring, space reuse), and adds capabilities defined in the later SQL standards. The major areas of enhancement are:

经过多年开发后,PostgreSQL 在很多方面都具有了完备的功能。这次发布定位于添加功能(例如授权、监控、空间回收),以及添加最新 SQL 标准中的新功能。主要的增强在于以下几个方面:

  • Windowing Functions Windowing 函数
  • Common Table Expressions and Recursive Queries 通用表表达式和递归查询
  • Default and variadic parameters for functions 函数的默认和动态参数
  • Parallel Restore 并行恢复

  • Column Permissions 列权限
  • Per-database locale settings 每数据库区域设置
  • Improved hash indexes 优化哈希索引
  • Improved join performance for EXISTS and NOT EXISTS queries 对于 EXISTS 和 NOT EXISTS 查询优化了查询性能
  • Easier-to-use Warm Standby 易用的温备
  • Automatic sizing of the Free Space Map 可用空间映射自动伸缩
  • Visibility Map (greatly reduces vacuum overhead for slowly-changing tables) 视界映射 (大大缩减了很少变化的表进行优化的负载)
  • Version-aware psql (backslash commands work against older servers) 依赖版本的 psql (旧的服务器上没有的反斜杠命令)
  • Support SSL certificates for user authentication 支持 SSL 认证的用户身份验证。
  • Per-function runtime statistics 每函数运行时统计
  • Easy editing of functions in psql psql 函数更容易编辑
  • New contrib modules: pg_stat_statements, auto_explain, citext, btree_gin 新的附加模块:pg_stat_statements, auto_explain, citext, btree_gin

说明:

PostgreSQL 8.4 Releas Note 我已经翻译完成,完整版本在 http://zerolab.co.cc/?q=node/6 但是我估计我那个免费空间抗不住这么大访问压力,所以会逐篇把主要内容放在这里。

该文档使用 Emacs Muse 编写。

这段时间我会自己开发或者搞一个 Muse2Wiki 的插件,把文档放到 PG 中文社区的 WIKI 上。

 原文地址 http://www.postgresql.org/docs/8.4/static/release-8-4.html

--
话题越大,废话越多;名字越火星,问题越脑残。
……

劉鑫
March.Liu

2009年6月30日星期二

jQuery 风格的HTML文本转义

astinus开发过程中,我自己就在不断的使用。有次贴了一些JS代码进去,于是页面显示错误。显然,把源代码直接放进html文本了——好吧,从05年转去做网游以后,一直没有正经的做过web了。

那么,我需要一个方法转义。网上搜了一下,大部分是自己编写一个正则替换。不过我的习惯是尊重既有的资源。有人提出可以用dom的功能。先作为innerTEXT传给一个dom对象,再取innerHTML属性,就可以取到转义后的文本了。

方法不错,不过写法上,有没有取巧的办法呢?

JQuery社区有人给出了办法:假设有文本 context,可以对一个jQuery对象 $(x)进行 $(x).text(context).html(),就会返回一个转义后的文本。

其实刚刚想起来,很多时候完全可以用text()函数对jQuery对象赋值就好了……



--
柳文扬先生逝世两周年祭
……

劉鑫
March.Liu

终于装成了Vbox 3.0

自从 Virtual Box 2.1.4 之后的版本我就从来没有升级成功过。运行安装程序就会提示不能打开临时目录。直到昨晚下载了Vbox 3 。终于出错提示多了点,这次提示打不开我用户名(刘鑫)下的临时目录打不开。更重要的是,提示我"unicode"路径无法解析。
显然,近几个版本的vbox安装文件,使用了一个只认识英文字符的打包工具。于是我建立了一个英文名的用户,切换过去,安装成功。

……

劉鑫
March.Liu

2009年6月26日星期五

空调坏了

用着用着突然发出爆响。开窗一看压缩机在外面台子上跳舞,伸出之手都按不住。只好关了。
刚才把插头插上,一开风扇,不转,把我悲痛坏了,我想这叫祸不单行么。
然后仔细一看,我插的电蚊香。

--
杀人放火金腰带,补路修桥无尸骸。

……

劉鑫
March.Liu

2009年6月22日星期一

Re: web2py 正式支持 order by desc

2009/6/23 刘鑫 <march.liu@gmail.com>:
> 昨晚做gastinus的消息编写页,发现orderby="post_on desc"居然出错,进去gluon里的源码一看,跟以前不一样了(刚更新了服务器代码)。于是搜索了一下文档,发现关于orderby的文档更新了,现 在DAL的orderby不再支持"fieldname desc"的形式,而是通过=~实现同样的功能。例如,gastinus的发言页面,需要按post_on倒排,应该写成
>
> db().select(db.quotation.ALL, orderby=~db.quotation.post_on)
>
> 这样确实比以前可读性更好,而且因为逻辑实现在代码而不是字符串里,更利于开发工具实现错误检查。
>
> 另外,GQLQuery似乎没有limit,只有limitby=(lmin, lmax)这样一种写法。其实GQL本身的limit语法与关系型数据库的普遍实现并无二致,不明白为何不统一。

所以,真男人就用男人版 ~ Trunk 的!


--
http://zoomquiet.org
'''过程改进乃是催生可促生靠谱的人的组织!'''
KM乃是培育可催生自学习型组织的文化氛围!

web2py 正式支持 order by desc

昨晚做gastinus的消息编写页,发现orderby="post_on desc"居然出错,进去gluon里的源码一看,跟以前不一样了(刚更新了服务器代码)。于是搜索了一下文档,发现关于orderby的文档更新了,现 在DALorderby不再支持"fieldname desc"的形式,而是通过=~实现同样的功能。例如,gastinus的发言页面,需要按post_on倒排,应该写成

db().select(db.quotation.ALL, orderby=~db.quotation.post_on)

这样确实比以前可读性更好,而且因为逻辑实现在代码而不是字符串里,更利于开发工具实现错误检查。

另外,GQLQuery似乎没有limit,只有limitby=(lmin, lmax)这样一种写法。其实GQL本身的limit语法与关系型数据库的普遍实现并无二致,不明白为何不统一。

2009年6月3日星期三

[Web2py]Web2py DAL 与 Postgres数据库

在诸多Python 数据访问框架中,Web2py的DAL算是比较有趣的一个。因为工作的关系,最近比较关注DAL与Postgres的组合。这里简单总结一下。
开头又臭又长,建议跳过,留着娱乐时间再读。直接从下一集开始阅读

数据存储与访问——理想与现实的妥协
在IT界,从来没有一个系统边界可以像数据库与应用层之间这样不断摩擦,冲突激烈,没推倒前的柏林墙庶几近之。不同的是同胞之间的藩篱终于在两德人民之间轰然倒下,而数据库与应用层的斗争只会光华灿烂,鸡飞狗跳。
鹅,写错了,是光华灿烂,旦复旦兮。几年不读圣贤书,已经赶不上语文课代表啦。
是的,应用层与数据访问层的关系,只会在冲突和妥协中不断发展和变化,周而复始。
为了吸引用户,满足需求,数据库开发者总是在努力丰富服务器端的功能。从Key/Value到层次存储,网状关联,再到平面表,再到关系数据库,再到复杂数据类型和过程化编程,再到事务、存储过程、甚至嵌入式混合编程,以及咸鱼翻生的MapReduce,千奇百怪,不一而足。(当然,类似分布式存储,裸设备访问这些NB的性能优化技术和存储技术也在不断发展,但这不是今天我们要讨论的问题。)
而为了吸引用户,降低学习成本,提高占有率,应用层开发者总是在努力提高代码的通用性。于是,在第一代数据库SDK直连的理念后,顺理成章的出现了ODBC这样的通用驱动桥接层。由于各种各样的原因,ODBC始终也没有实现一统天下的目标,JDBC等平台专用链接库层出不穷,就连老东家微软都忍无可忍推出了ADO和ADO.NET,于是,这一层的访问方式基本稳定在了一种运行时一个主流库的态势上,Java是JDBC、.net是ADO.net,Perl是DBX,Python统一这一层的是DBAPI。
但是,驱动桥接是面向数据行的,对于编程并不方便,需要应用开发程序员大量编写重复代码,手工维护连接,遍历得到的游标记录集等等,这甚至对于数据库服务器也不够友好。于是,我们看到,ADO.net中开始强烈的倾向一种自动生成对象结构的自动化编程趋势,而这个思想在Java中最先成为一个诱人的产品——Hibernate,这就是ORM。
其实大家都明白ORM付出了比较高的性能和功能代价,但是ORM对生产力的提升是不可抵挡的诱惑,各个平台纷纷陷落,还出现了不同的框架自己实现ORM的场面,Python尤其明显,这对于忠诚的"统一标准"信徒,简直是一件无法无天大摇其头的荒唐事。
于是,现在对于数据存储访问,就出现了一个相对比较稳定的分层,最下面是RDBMS以及其它数据库,不过这里我们只讨论最主要的RDB应用;上一层是各种桥接层,现在的趋势是每种数据库针对每种运行时提供自己的桥接层,以达到最优的功能和性能接口,而过去由ODBC、BDE、OLE DB这些系统桥接工具提供的通用性和移植性的黑锅,就由Hibernate们背了起来。
也许Python的生产力真的是太高了,以至于即使出了几种广受好评的ORM(例如SQLObject、SQLAlchmy、Storm)之后,Django、Web.py、Web2py等web框架还是实现了自己的ORM,这其中有些是在通用ORM上实现的,有些则是框架直接基于数据库访问接口组建的。而Web2py的DAL(Database Abstraction Layer),算是其中相当有趣的一个。

DAL的取舍
如同前面所介绍的,为了使得ORM组件吸引更多的用户,获得更大的通用性,通常都会牺牲数据库层的功能,作为一个年轻的ORM工具,DAL只能做到对最常见,也最简陋的MySQL和SQLite为目标进行了支持。事实上,即使MySQL的编程语法,也做不到完全的支持(至少,MySQL的全文检索就没有支持)。调侃一下,我印象比较深刻的数据库,如果编程能力打个分,大概是下图这个样子。
http://picasaweb.google.com/March.Liu/Blogger0=2#5343071442111853506
忘了加sqlite了,不过那东西也就是个40分的样子。而DAL能直接支持的,也就在这个40分的程度上。
不幸的是,我工作中用到的,恰恰是那个编程能力最强的,在我看来可以给100分(倒不是说就是满分)的PostgreSQL。
有功能不用,倒是不一定就会有什么不好,但是如果可以充分了解ORM层和DB的功能特性,就可以尽可能的发挥这两层工具的能力,提高工作效率和产品质量,精益求精永远都是一件好事。
这里简单介绍几个DAL及相关的技术特色,具体的技术细节凡是可以直接在文档中查询到的,这里就不细讲了。

数据库连接定义

DAL用来连接数据层的,是DB,对应通常的关系型数据库,是SQLDB对象,对应GAE Bigtable,则是GQLDB,这个对象是DAL整个访问操作的核心。当然,一个web2py实例内可以同时存在几个DB对象。
首先DAL的构造接口非常简单,只需要一个URI格式的字符串。例如,对于astinus项目的企业版,这个uri是postgres://astinus:march@127.0.0.1/astinus,包含了用户名、口令、服务器种类、位置、数据库名。虽然比起逐个参数进行指定的方式略为复杂,但是由于格式非常符合我们对于web url的使用经验(其实是现有uri的概念,才有了url这个具体的东西),所以非常好记。DAL支持的完整的DB列表及连接方式,可以在DAL的文档 http://web2py.com/examples/default/dal 中读到。
另外DAL针对一些数据库,例如Postgres,还提供了一个可选参数:pools,也就是数据连接池。有兴趣的朋友可以在glon/tools.py中找到这部分代码。
当然,DAL的连接定义也不是完美的,这里主要问题表现在两个方面:
  • 一定要指定password,有些数据库允许密码之外的身份验证方式,这样可以提供更可靠的安全性,但是DAL目前还只能使用密码验证。
  • 不能指定schema。对于PG和Oracle,不得不说是个遗憾。其实实现schema支持并不是一个很麻烦的事情,Web2py社区早有用户提过一些方法,我自己也想到过几个,例如采取类似trac DB URI的n参数方式就不错。目前我对此采用了一个妥协的方法:设定连接用户在数据库环境中的的search_path变量。这样就允许用户访问postgres数据库中public之外的schema,以及可以指定schema搜索顺序。
数据库结构定义与对象映射

DAL通过调用define_table方法,可以定义数据表,表结构中的field字段由SQLField对象构造。这种结构使得DAL可以定义丰富的字段约束信息,DAL提供以下特色功能:
  • 假设有SQLDB(或GQLDB对象)对象db,通过db.table或db['table']就可以访问指定的表table,再进一步可以访问表中的字段:db.table.fileld。这样就可以用应用层程序员习惯的对象结构构造查询和访问数据
  • DAL的SQLField对象可以提供非常丰富的数据约束条件,通过SQLFORM对象,可以快速构造带有页面、应用服务器、数据库三层数据验证约束的数据访问层次。
  • DAL可以同步数据库结构,也可以通过migate=False禁止这中同步。
  • Web2py提供内置的Database Administrat 界面。
同样,DAL的数据库结构定义功能也有一定的不足:
首先,同样是schema问题
  • postgres提供强大的text类型(不同于MySQL等数据库中常见的Text类型),但是在DAL中string无法充分利用这一功能。
  • postgres提供一个基本功能的XML类型,支持xpath 1.0和dom访问,但是同样DAL无法利用。
  • DAL定义的表结构一定要带有一个整数自增字段列作为主键,这一点不如django灵活。
  • DAL定义的表结构,外键定义非常简单好用,但是也不够灵活,不能指定非主键列(可以放在验证中,这样可以看作是实现了外键约束)。
  • DAL可以支持导出数据,但是不如Django按对象导出那么强大。
  • DAL的pg实现使用char(1)作为逻辑类型,而PG自带了真正的boolean。
  • DAL无法映射存储函数,而这时PG中非常强大的一个功能。
基于以上原因,我总是手工在数据库中建立表结构和相关对象,并且在define_table中设定关键字参数migrate=False。
DAL 的检索

DAL的数据检索(对应SQL select)做的很有意思。它可以支持:
  • 局部化选取,只读取表中一部分字段。
  • 支持连接查询,甚至支持左外连接,外连接在一些ORM工具中没有提供。
  • 由上两个技术,DAL可以支持相当灵活的查询集组合。
  • 子查询。
  • 统计计算,而且这个统计计算是基于SQL生成和惰性计算的,将计算放在服务器端,这是一个非常好的特性,而且使用起来很友好。
  • 服务器端排序和分页访问。得益于新SQL标准的关键字limit,DAL可以比较方便的提供分页查询功能,不过这个功能在MySQL上性能很糟糕(就海量数据集的场景而言),这个黑锅我想不能由DAL背。
  • 将查询集直接生成为多种输出,如XML、XMLRPC、CVS、JSON等。或者生成为SQLFORM以供web请求使用。

DAL的检索基本上是如下格式:
  • db(查询条件).select(字段列表,**{附加参数})
这是一个很经典的MapReduce格式
  • db(filter).select(map, reduce)
当然,在select函数中,也包含了个别filter操作(limit),这可以看作是对SQL语法的一种妥协。
同样,DAL查询也存在一些问题:
  • DAL不支持PG的全文检索运算符@@。
  • DAL不支持PG的正则表达式运算符~和~*。
  • DAL不支持FULL Join和Right JOIN,当然,这并不是很大的问题。
  • DAL不支持跨db对象的联接,即使它们指向同一个数据库。这一点我认为是合理的。
  • DAL查询集不支持完整的序列运算,不能切割,不能反向索引,这一点我认为是一种遗憾,应当改进。
我们这里不详解DAL的用法,有兴趣的朋友可以详细阅读DAL的文档,了解各种查询的使用方式。

DAL 的update、insert、delete操作

DAL也同样支持局部化的update/insert操作,这同样是很多ORM做不到的。在数据写操作时,DAL也有一些有趣的功能实现:
  • DAL允许 data={...}这样的局部化批量赋值,而db.person[0]=dict(name='Max') 则是一个非常巧妙的插入操作(DAL的id是从1开始计数的)。
  • DAL允许用Python的 del 关键字删除数据记录。
  • DAL的db对象支持commit和rollback。
  • DAL增删改查都可以方便的cache。
  • 可以从CSV批量导入数据。
  • 内置的curd辅助工具。
  • 可以方便的生成多种数据提供或RPC服务。
同样,我认为DAL在此方面也有一些地方有待改进:
  • ADO.net 支持定义增删改查对应的存储过程,DAL不提供此类功能。
  • DAL不能像Django一样提供基于业务对象的数据导入(XML或JSON格式)。
  • 仿dict接口的快捷访问非常漂亮,但是受限于id列,不能像django的get方法或ado.net的command.ExecuteScala(方法名记不清了)r一样直接构造单个对象选取操作。
进一步的,DAL虽然为db对象提供了executesql方法,但是却没有提供参数传入功能,也是一个比较明显的遗憾。

  • DAL的发展与讨论
我认为,针对DAL的PG应用,期待以下功能的实现:
  • 无id列,用户自定义主键的表结构,至少应该支持uuid。
  • 可以方便的指定schema范围或直接引用。
  • 更方便的外键定义。
  • 支持函数,最好可以自定义返回集结构,可以select query。
  • 至少应该提供参数化SQL执行功能。
  • 基于业务模型的数据迁移能力。
  • 更友好和强大的数据库管理工具。
  • 更充分和合理的利用PG的数据类型,如text和boolean。
  • 支持复杂数据结构,如数组、几何类型等。

--
杀人放火金腰带,补路修桥无尸骸。

……

劉鑫
March.Liu

2009年5月31日星期日

Astinus 文档格式

Astinus 文档格式

Astinus 项目需要支持相对复杂的通用文档格式,要能够描述多种格式化或带有元信息的文档。因此,需要约定一种通用文档格式。

数据格式

基本格式

Astinus文档的基本单位为条目,使用XML格式存储。根元素为 <entry id='uid'/>

文档条目的主体为 xpath:entry/content 在正文中允许嵌入元信息节点。

<entry/> 节点下允许加入其它节点,提供map类型的属性映射。

content 的 map 属性通过 xpath:entry/content[@*] 设置。

<entry/> 节点下不写入text属性

<cotent/> 节点下的信息是有序的

允许在 <entry/>内部嵌入<entry/>,或在 xpath:entry/content 内嵌入 <entry/>

数据退化

没有附加属性的情况下,可以没有<entry/>节点,根直接为 <content id='uid'/>

可以以XML字符串格式传递,默认的头是 <?xml version="1.0" encoding="utf-8"?>

数据表现层或新建文档输入项可以不提供uid,这样数据结构进一步退化为 <entry><content></content></entry>

JSON 转换

Astinus 文档允许表达为JSON 格式,也接受JSON格式的数据转入

JSON 格式的根是{id:'uid', cotent:[]},

数据表现层或新建文档输入项可以不提供uid,这样数据结构最大可退化为 [...]

content序列内,以字符串序列表达正文内容,序列元信息通过文本元素间嵌入的{}元素表达。

设计原则

Astinus 文档格式的设计遵循如下的原则:https://bitbucket.org/March/astinus/wiki/edit/AstinusDocumentFormat

  • 对应用层编程友好,尽可能支持通用编程接口。
  • 对存储层友好,容易存储和优化性能,允许在数据库端编程管理。
  • 自描述,在离开服务器支持的环境下可以解读
  • 非SQL表格,支持条目的非结构化字段表述
  • 允许文本化,添加全文索引支持
  • 尽可能少的保留字
  • 允许DAL信息的使用

Astinus 的文档处理环境遵循如下的原则:

  • 在应用层保持文档数据完整性
  • 允许提取元信息进行计算
  • 允许元信息编程
  • 允许版本化支持(考虑并发处理)
  • 允许解释DAL和嵌入式编程


--
杀人放火金腰带,补路修桥无尸骸。

……

劉鑫
March.Liu

2009年5月25日星期一

[web2py]DAL中隐藏的秘密:limit和orderby desc

web2py 有所有新兴开源项目的通病:文档落后于代码。
例如,你在document下的DAL相关文档里,只能读到orderby的用法,但是没有告诉你如何desc。在该文档中也找不到limit的介绍。
其实这两个功能都很重要,分页几乎是现代数据库应用中必备的功能,limit关键字就是为此而诞生的。而对于不能任意split(我查了web2py的源码才发现小于0的索引SQLROWS直接抛异常),又不能直接reverse的DAL数据集,倒排查询就是很重要的功能了。
其实这两个功能DAL都有。
oderby的支持看来开发人员还没有找到很好的形式,例如,我们可以 orderby=db.ta.id,但是没有一个descorderby=db.ta.id,不过其实我们可以 orderby="ta.id desc",这样看起来有点怪,但是可用,而且不算很难理解。
limit关键字参数的支持就自然很多,类似标准SQL,DAL的limit支持两种形式:
limit=n,取数据集前n项。
limit=(n,m)从m项起取前n项,等效于PG的limit n offset m
--
杀人放火金腰带,补路修桥无尸骸。

……

劉鑫
March.Liu

web2py 的自定义路径

Web2py不同于django和web.py的一个特色,它自然的就是restful的形式。当然这也造成了一定的限制,就是我们有时候不能方便的自定义请求的路径。
其实Web2py一样可以自定义请求路径。只是它默认情况下没有给出这个配置。简而言之,在web2py的根目录下有一个 routers.examples.py,只要看那个文件的内容,就可以参照着写出自己的routers.py了:)。它采用的是类似django和 web.py的正则表达式重定向形式。
--
杀人放火金腰带,补路修桥无尸骸。

……

劉鑫
March.Liu

web2py 的远程开放

web2py是一个有趣的框架,它的特色之一就是在页面上集成了一个简单的开发环境。但是这个前提是只能从127.0.0.1访问,否则会提示你"不是安全通道"。
那么,是不是就没有办法把代码集中部署到一个远程服务器上开发了?
后来,我在web2py的官网上搜索到一个方法,,就是通过ssh映射远程端口到本地,可以实现远程开发。例如,我在192.168.0.13主机上run了一个web2py示例:
python web2py.py -i 0.0.0.0

那么我就从本机:

ssh -L 8000:127.0.0.1:8000 192.168.0.13

登录之后,如果再从浏览器访问 http://127.0.0.1:8000 ,打开的就是远程主机的回环IP。此时,就可以对远程的站点项目进行开发了。由于Web2Py提供了编辑冲突保护,甚至我们可以用这种方法进行团队集中式开发。

当然,我还是建议尽可能走成熟的版本管理系统进行开发。一个比较好的模式是每个团队成员在本机有一个开发环境,在测试服务器上有一个集中的环境,成员通过分布式版本管理系统——例如Python和OpenJDK项目使用的mercurial,或web2py和ubuntu项目使用的bzr——与测试服务器上的中心仓库同步,就可以实现比较理想的写作效果。更严格的管理模式,可以使用一个SVN,然后对可集成的分支挂一个hook,使其可以在有用户commit后自动发布到测试/生产服务器。

在这种情况下,通过ssh远程进入web2py的开发环境,也可以帮助我们获取错误信息,仍然是一项很有意义的技巧。
--
杀人放火金腰带,补路修桥无尸骸。

……

劉鑫
March.Liu

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)

2009年2月22日星期日

中华田园老公

冷笑话一则。如题,余下自己想。

Trac 0.12 开发环境(二)设定测试用户权限

昨晚头痛,上一篇没写完,其实对于trac,如果你只是把htpasswd文件传给它,还是不能在web端配置,因为没有admin用户。

这个时候我们需要回到命令行下,用trac-admin来试试:

详细文档请见这里

简单的说,按我习惯的开发用户march,我要将其设定为当前这个trac应用的管理员用户:

trac-admin . permission add march TRAC_ADMIN

现在再启动trac,以march登录,就可以看到页面左上角多了一个"admin"链接。

这样,就可以使用march用户在web界面上继续管理工作啦。

2009年2月21日星期六

Trac 0.12 开发环境(一)授权

上帝说,要有光,所以就有光。
武总问,trac怎么设用户?所以就有了本文。
=======================
这是针对开发人员的,对于实际生产环境,可以选的用户认证方式有很多。公司这边现在用的LDAP,效果不错。
相关链接(更多内容可google):http://trac-hacks.org/wiki/LdapPlugin

正式开场


对于开发人员,通常总是会选用tracd作为开发环境,无它,简单。 tracd支持所谓的standalone模式。基本的运行很简单:

tracd -p %port %path

但是这个时候点击login,只会看到这样的一个页面:

Trac Error

Authentication information not available. Please refer to the installation documentation.

TracGuide — The Trac User and Administration Guide


默认情况下trac需要它的前端服务器为其提供授权,比如apache或nginx,standalone的时候,得要自己准备一个口令文件,文档上给出了用htpasswd工具,或直接使用Python脚本来生成口令文件的方法

有了这个文件,我们就可以用basic-auth的方式使得我们的开发环境支持简单的用户登录:

tracd -p 8080 --basic-auth=trac,.htpasswd,trac .

这里的--basic-auth指定基本授权方式,它的格式是[项目目录],[密码文件路径],[realm]
虽然文档上要求全都写完整目录,但是实践证明相对路径也是可以的,以上命令是我执行成功的。
测试过程中如果看到浏览器提示可能因为拒绝cookie造成服务器循环引用地址而产生错误,很可能说明你的设置成功了,只要把地址指向login以外的位置,应该就可以正常访问啦。

Trac 0.12 安装

注:比起ZOPE系,trac的安装已经算相当的简单啦。

如果是release版的trac,我的建议就简单粗暴,你的系统提供什么软件包(或者你能在trac的主站上下到的包)。就直接拿来用好了。当然,release版的trac安装还是都很靠谱的,就算是源码版, sudo python setup.py install足矣。

developer版稍麻烦些,setup.py install的时候,你会发现它要求的genshi库版本自己找不到。其实,这时候可以先
easy_install -U "Genshi==dev"

,然后再回过头来继续安装吧。
接下来就按部就班的建站点,trac-admin %path% initenv。它会以问答的形式指引用户设定项目名、源码库、数据库(SQLite之外的用户移步这里)。
此时,启动tracd -p %port %path ,已经可以看到站点了。安装至此算是初步成功,祝你顺利:)。

附:其实这就是Django所宣传的MVT结构(Model View Template),trac可以说是比较典型的MTV应用。理解这一点,开发trac的插件或对它进行定制,思路就会清楚多了。

2009年2月6日星期五

今日流水帳

在私记薄里记录想法。
在即时贴里记录todo小tips,这些事项可能不会很正规,未经整理,强调的是快捷。
在公司wiki的todo页跟踪事务序列(Todo/Doing/Done)
养成做事前先明确的习惯。谋定而后动,坐言起行,不拖泥带水。
不要想太多,先做,详细记录,用到出问题,再找解决方法,比猜测需求要可靠的多。
事事留心皆学问。
发现GMail的POP接口每天能接收的邮件是有数量限制的--正常的人类也不会一天收三千封邮件吧。
小时候我爸妈帮我办了残疾人证,可能怕伤害到我的自尊心,没告诉过我,是我无意中看到的。
后来到了快三十才发现有这个可以免费进博物馆什么的,结果现在政府不承认我这样的算残疾了。
党的政策好了,我现在不残疾了!
不该买新鞋哇!
还好没在本子上继续训练分词,pos训练慢到吐血,这会儿我的台式工作机已经卡到不行。

2009年2月5日星期四

昨日流水帐

工作计划应该至少精确到小时,一个优秀的工程师应该可以精确到十分钟,虽然不一定可以百分百的达成。
人真的是有惰性的动物,记录时间帐单,催促自己提高工作效率。
记录自己将要做的事而不是刚刚做的事,推动自己从被动完成向主动做事的转变,养成每次只做一件事,做好一件事的习惯。
要锻练自己及时发现讨论跑题,并且要及时拉回来。
工作讨论,寻找共识比起战胜对方更重要。应该从大专辩论会那种“谁有理”转为沟通、理解、互利的角度。
OO表格在不同机器上有变形,导成PDF比较安全。

其实我要说的是,A正太昨天多了一个仰慕他的男FANS!恭喜A正太!

2009年2月4日星期三

流水帳

寒,写了一天的流水帐,save changes的时候opera居然死了,你丫狠,居然还清了我的剪贴板……
我现在等Acrobat Reader装完,查一下PG里yesterday是啥……
PG的Timestamp还分有时区没时区,还不能隐式转换,差儿坑死我。
trunc_date是个好东西。
extract是个好东西。

2009年2月3日星期二

流水帳

昨天准备把车上写的两篇关于Postgres的文章放到blog上,结果发现找不到了。想来想去,只有可能是因为手贱删了两个私记薄的备份文件。看来它现在学习MoinMoin,把版本记录到了历史文件中。这下我可不敢随便删文件了,还是把它存到一个独立的目录吧。
下午试着DONE了一下,果然不作save changes的话,它不会保存。
PGAdmin III启动,Tips 弹出一个:42是生命、宇宙和万物的终极解答。
结果我很没有面子的在例会时间笑出声了,NND。

我干了一件很白烂的事,写了一个联接查询,把一百多个IP重复ping了两遍(其中大部分是ping不通的),多等N久,明天把時間賬單的報表查出來就知道了……
这种时候应该用表子查询。

2009年2月2日星期一

ubuntu 的 postgreSQL

ubuntu上其实有PostgreSQL的安装包,sudo apt-get install,就可以直接使用,但是刚开始的时候这个包也给我弄出不少麻烦。以至于有很长一段时间我宁可使用源码自己编译。总结一下,比较容易给新手造成麻烦的地方有这样几个:

ubuntu上PostgreSQL的超级用户是postgres,与官方文档一致。而bsd上是psql。

ubuntu上的pg命令行工具名为psql,bsd上是pgsql。

pg_ctl找不到?但是ubuntu上有一个pg_ctlcluster,它可以帮你完成pg_ctl的工作,只是需要一点题外的东西:
ubuntu 将PostgreSQL的服务器按集群管理(我是不太想在一台硬件主机上架一个“集群”那么多个PostgreSQL实例,那跑起来能快吗?做开发和学习测试还差不多)。因此执行pg_lsclusters,你会看到一个集群列表。默认是只有一个。用pg_cltcluster管理服务器的时候,你要比pg_ctl多指定一个版本号,一个集群名,就是从这里来的,不知道该指定谁的时候,可以查看pg_lsclusters。

在apt安装以后,pg实例就自动运行起来了,如果想要手工控制,同样使用pg_ctlcluster。如果想参考一下apt的pg启动配置,推荐看一下/etc/init.d/postgresql-8.3(或者你自己安装的那个版本)脚本。

默认的数据区不在postgres文档所推荐的/usr/local/pgsql/data,而在/var/lib/postgresql/8.3/main/。而配置文件在/etc/postgresql/8.3/main,到时候不要找不到pg_hba.conf哦:)。

contrib目录在/usr/share/postgresql/8.3/contrib/,安装插件什么的一定会用到。

安装bamboo的时候,我有很久找不到pg_conf跑哪里去了,这也是我早先使用pg源码的一个非常非常重要的原因。其实这个命令在postgresql-server-dev-8.3里。万恶吧!我google了好久才找到……

书店偶历

春节生活回顾。

和太太出門逛街,本來是要去安泰找相機維修店的,結果相機沒修成,半路倆人又溜進了圖書城。存了包,兩個人各投所好,她去裝潢家居,我去IT區。
實體書店的IT柜,我沒見過一個不囧的。CCNA與HTML比鄰,LINUX管理與Windows入門相伴。總算安泰強過閩臺,竟然C專柜沒有見到C#的教程,而且知道VC專列一柜,大大的讓人刮目相看。VC和VC#混在一起,我想就不必強求了。
大概太久不逛實體書店,來到C++柜,居然不見當年那些《STL源碼剖析》等老面孔。雖然確實過了好幾年,但是現在還是覺得好書永不過時。想到現在的年輕人讀不到這些好書,還是為他們有點小遺憾。
又 見到《C++大學教程》,這本書當年買來一直沒有讀進去,最后送給了同事。想想也許邱仲潘老師的譯本確實有些毛病,但是自己心浮氣躁應該還是主要問題。這 次見到已經是第五版了,希望以后買到這本英文版的朋友不會像我當年一樣半途而廢,C++是一門需要花時間學習的語言,如果做不到勤奮二字,再好的教程也沒 有用。
赫然看到一本比《C++大學教程》更厚的《C大學教程》,仔細揉了揉眼睛,發現英文標題真的是跟《C++大學教程》對應來的,真的不是BT 吖。心說《C Programming Language》不過二百多頁。這本大學教程能翻出什么花樣寫出千把頁的內容?了了翻過不禁莞爾,原來這作者把C/C++/Java來個一勺燴,還夾雜 進去一堆GUI編程之類的東西,難怪能如此肥大。想來如果是某些逢中文書必貶,豆瓣收藏都是英文影印書的IT裝13青年,倒是大大的和此書的意境。確實大 家評選垃圾書的時候,多關注的是國內的剪刀黨,或者機器翻譯風格的家伙,原文書普遍來說,還是比較有保障。但是前有21天精通XXXX系列,后又出了這個 《C大學教程》,充分說明了遠道的和尚一樣不少瞎念經的,以后垃圾IT書排版也應該分出不同的類別,比如原創垃圾書、翻譯變寶為廢、洋垃圾等等才是。
本 來也沒什么目的性,就是瞎轉一番,看到一對中年夫妻擠在VC柜討論了半天,聽不清說什么,走進去看看沒有自己喜歡的書,連VC++編程內幕這種當年的基準 資料書都沒有。不知道是我老了還是這家書店太out了。看到一本關于多核程序設計的書,頁數不多,但是內容很實在,簡單質樸,翻了翻,類似性能評估,并行 算法之類的介紹很有一些,而不是簡單的講講API。對比下自己買的那本,頓時覺得虧到了。小小遺憾下,還是恭敬的放回去,希望能遇到識貨的買家。
偶 然間看到了《編程珠璣》,這本書發售當時是大大的火了一番,但是我這人天生別扭,買書偏不喜歡與流行時,眾人說好的往往避之不及。今天看到,想起當年曾有 個家伙說我發表在《程序員》上的某算法講解是抄襲自此書,心血來潮,便拿起來翻翻。沒想到內容居然是大大的喜歡,知識講的簡單清楚,橋段也八的津津有味。 讀到美國人構想從衛星上發射電纜到地面以建立高可靠的通信網絡,甚是心馳神往,六七十年代的美國佬上九天登月,下五洋捉鱉,端的是激情澎湃。越讀越覺得與 此書甚是有緣,便不管安泰不打折,拿了前后兩冊結帳去也。

2009年1月18日星期日

鸡蛋三明治

喜欢半夜做宵夜的日子,玉米沙拉,意粉,鸡蛋三明治。
其实鸡蛋三明治很简单,重要是煎蛋时的手感。
  • 先准备好面包片,摊好。
  • 菜片,生菜叶或其它喜欢的生食菜品,铺好,我喜欢这个时候就涂沙拉酱上去。用两片面包就夹好它。摆在盘上。
  • 升火,火不能太大,要有平底锅,少少油,轻轻的把蛋打下去,慢慢看它成形。等底部煎定型以后视情况铲起来滑一下,免得焦底。出锅不太早,不然会完全流掉,也不能太老,就不好吃了。以最上面的蛋白定型,可包住蛋黄为宜。
  • 把蛋直接摆到面包片上,油多的话可以先控下油再摆。
  • 然后把夹着菜的面包片摆上来。
  • 经验上来说,最好不要直接在蛋上涂沙拉酱,感觉不好吃。

好喜欢太太吃到三明治的时候开心的样子,上次的早餐煎得有点糊,太手忙脚乱啦。

2009年1月4日星期日

Bamboo 安装指南

  • 文档属主: 刘鑫

  • 目标读者: 软件事业部全体员工
  • 版本历史:

环境需求

实现本文过程使用的环境如下: ::

  • Ubuntu 8.10
  • gcc 4.2
  • g++ 4.1
  • PostgreSQL 8.3.5

关于 Bamboo

Bamboo项目是一个中文语言分析引擎,开发者是Postgre领域久负盛誉的eeee团队。目前使用者还不算多,但是从http://code.google.com/p/nlpbamboo/wiki/Benchmark|测试数据来看也有着不错的成绩 。它最大的亮点是集成了PostgreSQL接口。

Bamboo项目提供DEB、RPM等几种格式的安装程序,不过源码编译也很方便。

参考资料

Bamboo 项目站点

Bamboo 安装入门

PostgreSQL 数据库系统 *NIX 简易安装指南

Bamboo 与 Tsearch2 的集成配置

环境准备

CRF++

编译Bamboo需要CRF++库支持,可以从这里下载

CRF++的安装并不复杂,标准的configure/make:

./configure
make
sudo make install

但是此时如果编译Bamboo,会提示找不到libcrfpp.so.0,因为默认情况下crf安装到/usr/local,我们可以修改path,也可以configure的时候指明--prefix参数。这里我建立了一个ln:

sudo ln -s /usr/local/lib/libcrfpp.so.0.0.0 /usr/lib/libcrfpp.so.0

CMake

Bamboo 安装需要cmake支持,在ubuntu下可以用apt安装:

sudo apt-get install cmake

安装

假设用户位于~/third-party目录下,Bamboo的源码包在~/downloads下:

tar vxf ~/downloads/bamboo-1.1.0.tar.bz2
cd bamboo-1.1.0
mkdir build
cd build
cmake ..
make
sudo make install

默认情况下bamboo安装在/opt/bamboo目录下,此时的bamboo还不能直接使用,因为需要辞典,训练过程很简单,详见Bamboo 安装入门。简单来说可以这样:

sudo /opt/bamboo/bin/autobuild -t crf_seg

这个过程非常漫长,在AMD 2300+ CPU,1G内存,kubuntu 8.10的机器上用时超过了12小时。我没有尝试,但是也许可以直接把编译生成的data和index目录复制过去使用。

Bamboo项目现在还支持词性、实体词和主题词分析,详见Bamboo 安装入门

PostgreSQL 集成

要在PostgreSQL中使用全文索引,首先应该安装Tsearch2引擎,详见PostgreSQL 数据库系统 *NIX 简易安装指南

配置好PostgreSQL后,进入Bamboo目录安装PostgreSQL支持,在默认设置下,我们需要编辑一下Make命令,将PG_CONFIG 指定为 /usr/local/pgsql/bin/pg_config。执行命令如下:

cd /opt/bamboo/exts/postgresql/chinese_parser
make
sudo make install

形式上我们需要一个stop word文件,实际上bamboo并不需要它的支持,所以可以在如下位置(默认安装路径)建立如下的空文件:

/usr/local/pgsql/share/tsearch_data/chinese_utf8.stop

接下来以超级用户登录到需要支持中文搜索的数据库,执行:

# \i /usr/local/pgsql/share/contrib/pg_bamboo.sql
# \i /usr/local/pgsql/share/contrib/chinese_parser.sql

如果没有错误,就可以执行SQL测试一下分词效果了:

select bamboo('中文分词');

SELECT to_tsvector('chinesecfg', '我爱北京天安门');

2009年1月3日星期六

PostgreSQL 数据库系统 *NIX 简易安装指南

环境需求

实现本文过程使用的环境如下: ::

  • Ubuntu 8.10
  • gcc 4.2
  • g++ 4.1

本文涉及的内容同样适用于KUbuntu,其它Linux可能在启动设置上略有差别,编译与安装过程也同样适用于类似的UNIX操作系统。

参考文献

PostgreSQL 8.3.5 Document : Install Procedure

注意事项

很多Linux发行版的软件库中都集成了 PostgreSQL。例如ubuntu可以通过

sudo apt-get install postgresql

命令直接安装。但是ubuntu的postgresql做了一些定制,命令行位置、调用格式等都略有差别,对于只有官方文档的学习者,可能自己编译更容易掌握和学习。

安装过程

=== 获取代码 ===

  • 下载 Postgresql 的源码(当前最新版本是 8.3.5)。

  • 解压(这里假设下载至~/downloads)

tar vxf ~/downloads/postgresql-8.3.5.tar.gz
  • 进入解压后的源码目录

cd postgresql-8.3.5

配置与编译安装

  • 执行配置命令

./configure

应注意阅读这一步输出的信息,可能你的系统中缺少一些依赖库,可能你想要添加一些其它的设置,如我在这里编译时调用的是:

./configure --with-python --with-perl

* 编译与安装

make
sudo make install

这样编译安装后,数据库位于/usr/local/pgsql目录。

扩展

PostgreSQL 的一些扩展功能,例如tsearch2全文检索,默认不会安装。需要手工安装(使用linux发行版的集成版本时,可能需要单独指定其软件包安装)。

这个安装过程也很简单,只要在源码的contrib子目录下执行make:

cd contrib
make
sudo make install

配置与启动

配置基本信息

首先,PostgreSQL需要一个名为postgres的系统帐户做为默认的超级用户。$pg_path/bin目录下的命令需要以这个用户的身份执行。

sudo adduser

(或许你需要用passwd命令给它设定一个密码)

建立默认的数据存储位置,我遵循文档设定,建在/usr/local/pgsql/data。

sudo mkdir /usr/local/pgsql/data

接下来,要将这个目录的所有权赋给postgres。

sudo chown postgres /usr/local/pgsql/data

然后,初始化数据库目录。这一步需要切换到postgres帐户

su - postgres
/usr/local/pgsql/bin/initdb --locale=zh_CN.utf8 --encoding=utf8 /usr/local/postgres/data

从系统提示来看,ubuntu linux上“--locale=zh_CN.utf8 --encoding=utf8”已经是默认配置了,不需要干涉。

启动与运行

开发人员可以手工启动PosggreSQL,这也需要在postgres用户下。

su - postgres
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data start

pg_ctl可以控制服务运行,详见其help或PosgreSQL文档。

需要以守护进程模式运行在系统后台的话,可以手工配置。在contrib目录下有一个子目录名为start_scripts,分别有freeebsd、linux和osx上的启动脚本示例。这里只介绍linux脚本的使用:::

  • 将contrib/start_scripts/linux文件放到系统的init.d目录:

sudo cp linux /etc/init.d/postgresql
  • 然后建立六个符号链接,该脚本自己的示例是:

sudo ln -s /etc/init.d/postgresql /etc/rc.d/rc0.d/K02postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc.d/rc1.d/K02postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc.d/rc2.d/K02postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc.d/rc3.d/S98postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc.d/rc4.d/S98postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc.d/rc5.d/S98postgresql

然而我用这样的方法在ubuntu上不能启动,经梁庆喜指点,改为如下六个符号链接:

sudo ln -s /etc/init.d/postgresql /etc/rc3.d/S98postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc6.d/K90postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc0.d/K02postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc2.d/S90postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc1.d/S90postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc4.d/S98postgresql
sudo ln -s /etc/init.d/postgresql /etc/rc5.d/S98postgresql

重启即可。

测试

登录到postgres

先确认服务器处于运行状态。然后执行:

su - postgres
/usr/local/pgsql/bin/psql postgres

在此控制台环境下可以查看可用的命名(\?),可以查看SQL语法帮助(\help),可以查看环境信息(\SHOW ALL)。详请可以执行\?查看。

创建新用户

切换到postgres用户下执行创建命令:

su - postgres
/usr/local/pgsql/bin/createuser march

这样会将我系统中的 march 用户与之关联起来。

创建数据库

切换到postgres用户下执行创建命令:

su - postgres
/usr/local/pgsql/bin/createdb -O march UniSearch

-O 参数指定这个数据库的所有者为march。

信任授权

如果从网络无法访问数据库,提示连接被拒绝,可能是权限问题,此时打开数据库目录下的pg_hba.conf,找到类似如下格式的文本(通常在最后):

# IPv4 local connections:
host all all 127.0.0.1/32 trust

将需要信任的IP加入,设为trust。或按照注释文档中的说明进行配置。

附录

INSTALL 文档中的 Short Version 一节

./configure
gmake
su
gmake install
adduser postgres
mkdir /usr/local/pgsql/data
chown postgres /usr/local/pgsql/data
su - postgres
/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data >logfile 2>&1 &
/usr/local/pgsql/bin/createdb test
/usr/local/pgsql/bin/psql test