一次数据库的选型,FireBird胜出
做了n多年的J2EE应用以后,如何做客户端的BI确实让我一下子摸不到门路。近期的一个客户要求我们给他做基于客户端的BI分析,客户是对外提供重要数据的单位,有很多的客户每年购买他的数据。可以说人家的数据库,每行每列都是钱。在这种情况下,他们非常害怕入侵,甚至数据都不会放在网上。之前提过很多的方案,从标准的BI平台到客户端采用Web service方式连接服务器获得数据,但是最终都因为“要让数据放在网上”而被枪毙了。
最终确定的设计是采用客户端,也就是说,将客户端的BI工具分发给客户的客户,每月再由客户通过邮件、光盘等方式将付费的数据采用加密的方式传递给数据使用单位。这些单位收到数据后,在客户端打开,客户端负责解密和展示。
BI部分我轻车熟路,由于要“分发”,所以只能选择Opne Source的,我比较看好Jasper Report,可以培训他们使用Ireport做报表,然后将做好的定义文件打包一起分发;客户端程序也不复杂,只需要修改Jasper的viewer就可以了。
除了担心Ireport太次,容易让客户使着使着抓狂(这就是后话了,实在逼得不行,只能围绕IReport再作开发了,好在都有源码)之外,近期最让我烦恼的就是如何选性数据库。要说BI平台数据库的选型,参加革命一两年的同志就可以说出一大堆各种数据库的对比,但是那些都是大型的,反而小型的这次把我难住了。
研究了一圈以后,获得提名的数据库是他们几个:
- access:数据类型有些另类,而且密码太容易被攻破,最大的问题在于要为此付费;
- hsqldb:这是最可能成为胜利者之一的数据库,支持csv,配置分发容易,但是最终败北在性能上,当单表数据量在100万以上的时候,csv文件达到40兆,执行group by的sql语句用了300秒!这和sql执行效率无关,性能瓶颈在硬盘文件上,毕竟由于hsqldb没有在数据文件存储上花时间,只是挂个csv;
- firebird:看标题就明白,这是胜利者,下面我会说说它的好处。
- sybase asa:数据能加密,性能不错,但是败在“需要付费”上;
- derby:它和fb有一拼,不管在性能上还是在易用性上,但是最终有两点不如fb,第一、embedded版本完全没有数据认证,导致谁都可以打开数据库执行sql语句;第二、数据库是以一个目录存储的,而fb只有一个文件;
- sqllite:不支持数据加密,另外,对中文,尤其是用中文order by的时候时常错误;还有就是完全没有用户认证;不过据说执行效率不错;
- mysql:要说最像样的就是这个了,但是严格说起来,虽然mysql也可以不通过安装,直接拷贝就能使用,但是距离embedded还差一块,所以不考虑了。
行了,言归正传,最后firebird胜出,很荣幸的成为这个项目的数据库。原因有这么几个:
- 数据文件是单一,部署、分发相对简单;
- 用户不需要安装,像这个项目,只是用embedded方式,只需要把icudt30.dll、icuin30.dll、icuuc30.dll、jaybird21.dll、fbembed.dll五个文件和目录intl(里面有两个文件,是处理字符集的)放在程序启动目录就行了;
- DBC配置、引用比较简单,driver就是一个jaybird-full-2.1.6.jar,看了其他的一些资料,都搞不清他的lib目录里面的其他的jar是做什么的,仔细看说明以后终于明白,原来这个full版本就是其他几个的集成,为了调用方便,人家不但提供了集成,又给你拆开了,你爱用哪个用哪个。有点像Spring的2.5兆的jar和无数个几十k的小文件的关系。
- 中文支持的不错,但是要在建库的时候使用GB_2312字符集;
- 一个叫FlameRobin的工具也不错,起初有些别扭,窗口和窗口都分着,典型的Linux风格,后来习惯了;
最后附上embedded的连接例子吧:
long start = Calendar.getInstance().getTimeInMillis(); org.firebirdsql.pool.FBWrappingDataSource dataSource = new org.firebirdsql.pool.FBWrappingDataSource(); // 设定数据库文件 dataSource.setDatabase("TEST.FDB"); // 可以不设 dataSource.setDescription("An example database of test"); // 设定EMBEDDED就行了,说明上写着另外两种type是TYPE2和type4,干什么用的没研究,谁知道回一个阿 dataSource.setType("EMBEDDED"); try { dataSource.setLoginTimeout(10); // 这个地方是最让我痛苦的,设定了密码没用!下面会说。 java.sql.Connection c = dataSource.getConnection("user_1", ""); java.sql.Statement stmt = c.createStatement(); // 100万的大数据量 java.sql.ResultSet rs = stmt.executeQuery("SELECT count(id) FROM largedata"); if(rs.next()) { System.out.println("count: " + rs.getString(1)); } stmt.close(); c.close (); } catch (java.sql.SQLException e) { e.printStackTrace(); System.out.println("sql exception: " + e.getMessage()); } System.out.println("==>" + (Calendar.getInstance().getTimeInMillis() - start)/1000); // 在对id作了索引的情况下,你猜多久?1秒钟!同时做一个count和sum的group by,在没有索引的情况下40秒
补充一把:嵌入式数据库的让我最痛苦的是没有办法做安全设定,一位仁兄说得好:数据文件都给人家了,做什么也没用。
我觉得太有道理了,就拿Derby来说,完全没有安全性设定,谁都可以打开,FB呢,稍微好一点儿,不知道用户名就打不开(这是授权的事,说白了还是没认证),上面的例子,明明数据库的用户是user_1,密码123,但是不论你用什么密码,都能访问数据,但是如果你不知道用户名,就没戏了。
算是瘸子里拔将军吧。
后来,我还煞有介事的google了一把“firebird破解”,你猜怎么着,有高人出的高招:不知道用户名也能照样打开。怎么弄我不说了,万一让“客户的客户们”谁看到了,又要逼着换方案,这谁受得了。
不过说真的,要是谁知道embedded FB怎么保证安全,赶紧给我支两招,我都快疯了。