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