【IT168专稿】2010年岁末,国产数据库之一的南(开)大(学)通用到我们单位作技术交流,对我们已有的一个应用完成了数据库结构的迁移,并留下了一套安装文件。我终于目睹了了这个神秘的列式存储数据库的真容。给大家分享一下我的感受。
南大数据库的命名很有意思,用最后一位字母代表的英文单词来表示数据库的大致用途:g通用,s安全,a就是分析了。从命名可以看出,他们的思路是按用途来细分产品,而不是像Oracle那样在创建数据库的时候由用户指定用途来配置不同的初始化参数。按照软件界的常识,通用的软件性能一般不如专用,那么我们可以想见,这个分析型数据库的分析性能应该比较好。
列存储数据库是相对于传统的以记录或数据行(Record,Row)为单位进行数据处理的数据库来说的,它以数据表中的列(Column)为单位对数据进行存储和查询等处理。传统的以记录为单位进行查询处理的数据库如Oracle等又称为行存储数据库。列存储数据库的主要优势在于采用了以数据列为单位进行存储的模型,该存储模型非常有利于对数据库进行高效的压缩从而减少数据规模。此外,基于列存储模型的查询分析器与传统的行存储模型相比,节省了存储空间和I/O带宽,从而提高了数据库的性能,特别是在数据规模比较大的情况下,列存储数据库更有性能优势。
GBase的存储和索引技术参见《GBase 8a数据库技术白皮书》,这里不做深入探讨。
废话少说,下面进入我的简单评测环节。
一、安装
我用于测试的机器是一台4颗6核CPU的PC服务器,操作系统是简体中文Windows 2008 R2标准版,我用的安装文件是GBase8a_8.3.1.4_build3.6_Windows64.exe (91,043,199 字节),这是一个x64平台的安装文件,与目前其他主流商用数据库动辄几百兆甚至几个G的安装文件比起来,这是一个相当小的安装文件。安装界面全是图形交互式的,很简单,也没有太多配置项。只有一个root用户的口令需要输入,进行到这一步时我有些奇怪,不是数据库用户吗,怎么叫root?而且像一个Unix操作系统的用户?可能是为了跨平台的需要吧,但用户名应该是GBase 8a软件的设计人员可以自己设定的。
安装完成以后,在开始/所有程序下新增了一个GBase的菜单项,有企业管理器的快捷方式,数据库后台服务默认是自动开启的。
作为一个评测,我们并不急于开始使用,而是先看一下数据库安装在磁盘上的文件和目录。
2010/12/13 08:47 <DIR> .
2010/12/13 08:47 <DIR> ..
2010/12/13 08:47 <DIR> Config
2011/01/07 10:43 <DIR> GBaseStudio
2010/12/13 08:47 <DIR> JDBC
2010/12/13 08:47 <DIR> jre
2010/12/13 08:47 <DIR> ODBC
2010/12/13 08:47 <DIR> Server
2010/12/13 08:47 <DIR> StatusMonitorTool
2010/12/13 08:48 <DIR> Uninstall
如上图所示,安装程序在磁盘上创建了几个目录,分别用于存放配置信息、服务器、管理工具、状态监控工具、还包括一个java运行环境和数据访问接口。
再用tree命令查看详细的目录结构,可以发现,管理工具、状态监控工具都是基于java的应用。而其他目录相当简单:
F:.
├─Config
├─JDBC
├─ODBC
├─Server
│ ├─bin
│ ├─cache
│ ├─data
│ │ ├─gbase
│ │ └─test
│ │ └─t.GED
│ └─share
│ ├─charsets
│ └─english
└─Uninstall
└─resource
如上图所示,Server目录既是数据库服务器可执行文件的存放地,也是数据的存放地,share这个目录和前面的root用户名一样似曾相识。没错,这与mysql的目录结构相似,请看下面的MySQL 5.4目录结构:
D:.
├─bin
├─data
│ ├─employees
│ ├─mysql
│ └─test
└─share
├─charsets
├─chinese
└─english
目录相似以外,那么文件呢,这次我们分别比较gbase目录和test结构:
2010/12/13 08:47 <DIR> . 2009-09-29 10:09 <DIR> .
2010/12/13 08:47 <DIR> .. 2009-09-29 10:09 <DIR> ..
2010/11/06 13:26 12,884 bitmap_join_index.frm
2010/11/06 13:26 0 bitmap_join_index.MYD
2010/11/06 13:26 4,096 bitmap_join_index.MYI
2010/11/06 13:26 8,742 cache_access_info.frm
2010/11/06 13:26 0 cache_access_info.MYD
2010/11/06 13:26 1,024 cache_access_info.MYI
2010/11/06 13:26 8,820 columns_priv.frm 2009-09-29 10:09 8,820 columns_priv.frm
2010/11/06 13:26 0 columns_priv.MYD 2009-09-29 10:09 0 columns_priv.MYD
2010/11/06 13:26 4,096 columns_priv.MYI 2009-09-29 10:09 4,096 columns_priv.MYI
2010/11/06 13:26 9,582 db.frm 2009-09-29 10:09 9,582 db.frm
2010/11/06 13:26 880 db.MYD 2009-09-29 10:09 880 db.MYD
2010/11/06 13:26 5,120 db.MYI 2009-09-29 10:09 5,120 db.MYI
一目了然,不需要更多地说明了,从额外多出的表名可以推测,gbase用到了位图索引和访问信息缓存。这可能与gbase高效查询有关。再在test数据库中创建一些表来看test目录的对比:
2011/01/07 14:00 <DIR> . 2010/09/27 21:02 <DIR> .
2011/01/07 14:00 <DIR> .. 2010/09/27 21:02 <DIR> ..
2010/09/13 12:37 0 .empty
2010/12/13 21:44 9,856 hu41.frm 2010/09/27 21:06 8,554 d.frm
2011/01/07 14:10 <DIR> hu41.GED 2010/09/27 21:10 98,304 d.ibd
2010/12/13 21:47 10,140 ren41.frm 2010/09/21 09:48 9,856 hu.frm
2011/01/07 14:26 <DIR> ren41.GED 2010/09/21 10:00 402,653,184 hu.ibd
2010/12/13 09:12 8,658 t.frm 2010/09/21 10:31 8,688 t5_3_1.frm
2010/12/15 10:17 <DIR> t.GED 2010/09/21 10:31 98,304 t5_3_1.ibd
2010/12/13 10:00 8,714 tcube.frm 2010/09/27 21:02 8,660 tcube.frm
2010/12/15 10:21 <DIR> tcube.GED 2010/09/27 21:02 98,304 tcube.ibd
这下我们可以发现GBase和Mysql的数据文件有着明显的区别,我们知道,后缀名为frm的文件是表结构定义文件,后缀名为ibd的文件是innodb数据引擎的数据文件。那么我们可以合理地推测,GED后缀的目录下存放着GBase的数据文件。至于各个文件的具体含义,这里不准备深入探究,还是尽快转到数据库功能和性能测试上来。
二、数据库的功能
GBase是一个服务器/客户机模式的数据库,服务器端其实就是一个后台运行的GBase服务。我们可以在Windows的管理工具/服务中看到它已经被设置为默认自动随操作系统启动,这也意味着,我们基本上不需要人工地干预。在需要的时候可以用Windows管理工具启动和关闭它。GBase还有一种启动方式,在命令行输入GBased -- console启动,但这不是推荐的方式。
数据库的基本功能有CRUD(表的创建、插入、更新、删除)等方面,下面我们逐个测试。
GBase 8a提供的集成管理工具包括一个适合于初学者和非专业用户的交互式的表设计工具,也包括一个SQL文本编辑器,使用后者需要用户有一定的SQL基础,但只有这点基础也不够,还需要对GBase 8a的语法规范和数据类型等有足够的了解。比如: Decimal(30)是非法的,不是因为Decimal关键字非法,而是定义的数据长度超出相应类型的限制。因为GBase中Decimal最大长度是18,也就是8字节长整型数的范围,与Firebird等数据库一致。(参考文献1中提到gbase支持更长的数字类型,也许要下一个版本才会支持)
除了图形化工具,GBase还提供一个本身自带的命令行工具,界面和mysql也神似。
Enter password: ****
Welcome to the GBase monitor. Commands end with ; or \g.
Your GBase connection id is 39
Server version: 8.3.31.100
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
黑体部分可省略,工具会提示用户输入口令,口令字符以*号代替,这样具有较好的安全性。
有趣的是我们也可以用mysql客户端可以访问GBase服务端,但需要指定5029端口。
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 35
Server version: 8.3.31.100 100.1
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use test;
Database changed
mysql> select count(*) from test.t;
+----------+
| count(*) |
+----------+
| 1000 |
+----------+
1 row in set (0.00 sec)
成功地创建了表。下一步是插入数据,按以往的经验,用insert语句逐行插入涉及客户端和数据库服务器的多次解析和交互,一般是较慢的,能否把外部文本(csv)文件导入?还用mysql的方法在这里行不通了,load data infile命令报错。
ERROR 3 (HY000): Unsupport commond, please use gbloader.
而一时也猜不透gbloader的语法规格,只能退而求其次,用存储过程,不懂语法规则没关系,再用mysql的试一把,这下顺利执行成功了,只不过速度大大低于预期。
CREATE PROCEDURE `test`.`insert_1K`
( )
BEGIN
DECLARE v INT;
SET v = 1;
loop_label: LOOP
INSERT INTO t VALUES (mod(v,4),mod(v,5),mod(v,67),mod(case when mod(v,13)>0 then v end ,113),v);
SET v = v + 1;
IF v > 1000 THEN
LEAVE loop_label;
END IF;
END LOOP;
END |
call test.insert_1K()
执行时间 21479ms, 更新行数: 1。
再查阅mysql文档,了解到有个自动提交的开关,用set autocommit=off把它关闭,再次执行刚才的存储过程,速度就合乎常情了。
Query OK, 0 rows affected (0.00 sec)
mysql> call insert_1K();
Query OK, 1 row affected (0.05 sec)
mysql> commit;
Query OK, 0 rows affected (0.04 sec)
mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
| 2000 |
+----------+
1 row in set (0.00 sec)
GBase毕竟不是Mysql,有一些地方是独特的,需注意。
GBase默认创建的表存储引擎是express,可以用show create table命令获得,并且不支持其他的存储引擎,虽然不报错,但实际上仍保持gbase引擎:
Query OK, 0 rows affected, 2 warnings (0.06 sec)
gbase> show create table tisam;
-----------------------+
| tisam | CREATE TABLE `tisam` (
`a` varchar(10) DEFAULT NULL
) ENGINE=EXPRESS DEFAULT CHARSET=utf8 |
-----------------------+
从前面对GBase数据目录的分析可以了解,实际上GBase完全能够读取myisam存储引擎格式的表,只是不支持用户通过命令来创建其他的存储引擎的表。
分区是数据仓库的优化手段之一GBase 8a支持范围分区,可能也支持其他分区方式,就不一一试验了。
-> PARTITION foo_1 VALUES LESS THAN (TO_DAYS('2009-01-01')),
-> PARTITION foo_2 VALUES LESS THAN (TO_DAYS('2012-01-01'))
-> );
Query OK, 0 rows affected (0.08 sec)
gbase> insert into foo values(now());
Query OK, 1 row affected (0.07 sec)
gbase> select * from foo;
+---------------------+
| created |
+---------------------+
| 2011-01-10 16:45:14 |
+---------------------+
1 row in set (0.01 sec)
另外,GBase 8a不支持表的主键,也不支持用户自定义索引。
ERROR 1031 (HY000): Table storage engine for 'b' doesn't have this option
gbase> create index a on test.b(a);
ERROR 1031 (HY000): Table storage engine for 'b' doesn't have this option
祭出我用来测试的中等规模数据集,100万行记录,一个多列分组聚合查询。更新操作对支持事务的数据库是代价较大的操作,Gbase的删除支持delete和truncate table二种方式。
GBase的事务处理实现与Oracle等其他数据库有多处差别,在开发时需要引起重视。请看下面例子:
gbase> set autocommit =off; │
Query OK, 0 rows affected (0.00 sec) │
│
gbase> insert into test.t2 values('12'); │ /*会话1未提交,insert更改对会话2不可见*/
Query OK, 1 row affected (0.03 sec) │ gbase> select * from test.t2;
│ Empty set (0.02 sec)
gbase> commit; │
Query OK, 0 rows affected (0.11 sec) │ /*会话1提交,insert更改对会话2可见*/
│ gbase> select * from test.t2;
│ +------+
│ | a |
│ +------+
│ | 12 |
│ +------+
│ 1 row in set (0.02 sec)
gbase> delete from test.t2 where a='12'; │
Query OK, 1 row affected (0.02 sec) │ /*会话1未显式提交,但delete的更改对会话2可见*/
│ gbase> select * from test.t2;
gbase> rollback; │ Empty set (0.00 sec)
Query OK, 0 rows affected (0.00 sec) │ /*会话1回滚,但delete的更改已提交,无法恢复*/
│ gbase> select * from test.t2;
gbase> insert into test.t2 values('12'); │ Empty set (0.00 sec)
Query OK, 1 row affected (0.00 sec) │
/*会话1未提交,insert的更改对会话1也不可见*/ │ gbase> select * from test.t2;
gbase> update test.t2 set a='13' where a='12'; │ Empty set (0.00 sec)
ERROR 1015 (HY000): Can't lock file (errno: 1) │
gbase> commit; │
Query OK, 0 rows affected (0.06 sec) │
│
gbase> update test.t2 set a='13' where a='12'; │
Query OK, 1 row affected (0.06 sec) │/*会话1未显式提交,但update的更改对会话2可见*/
Rows matched: 1 Changed: 1 Warnings: 0 │ gbase> select * from test.t2;
│ +------+
gbase> insert into test.t2 values('14'); │ | a |
Query OK, 1 row affected (0.00 sec) │ +------+
/*会话1未提交,insert的更改对会话1也不可见*/ │ | 12 |
gbase> select * from t2; │ +------+
+------+ │ 1 row in set (0.00 sec)
| a | │
+------+ │
| 13 | │
+------+ │
1 row in set (0.00 sec) │
│ gbase> select * from test.t2;
gbase> commit; │ +------+
Query OK, 0 rows affected (0.01 sec) │ | a |
│ +------+
gbase> select * from t2; │ | 13 |
+------+ │ +------+
| a | │ 1 row in set (0.00 sec)
+------+ │
| 13 | │
| 14 | │
+------+ │
2 rows in set (0.00 sec)
如图所示,GBase可设置不自动提交事务,默认是在会话级的。但这个不提交仅对insert操作生效,其余DML,如delete和update,仍然自动提交,而且在不自动提交的时候,insert操作以后,新记录在发起命令的事务本身都是不可见的,如果此刻发出更新命令,则报错。
测试到这似乎也没多少可干的了,少量数据体现不出列式的优势,常用的CRUD别的数据库都支持。用简单存储过程模拟出的数据离现实太远,测试了也不代表实际生产环境,而已有的外部真实数据又难以加载。由于GBase 8a定位于数据仓库应用,批量数据加载的功能也是不可缺少的,这也怪不得GBase,谁让我是在没有技术支持的情况下自己摸索的。直到偶然用GBase 组合8.3版本号在网上搜到了《gbase ctl文件格式与gbloader方法》,一切都迎刃而解了。
还有一个工具值得一提,尽管它不是gbase数据库安装的一部分,却是gbase工程师在做技术工作中遗留下来的好东西,orato8a,顾名思义是一个从Oracle到8a的迁移工具,这个工具的提示信息也是令我眼前一亮,有种久别重逢的感觉。
这不就是楼方鑫SQLULDR2工具的命令行参数吗,它的前身ociuldr在网上有公开的源码,gbase将这个工具在64位Windows上编译了,更加符合普通非专业用户的需求。这个工具能产生csv数据文件对应的gbloader控制文件,如果用脚本适当编程就可以实现从Oracle到8a批量的数据迁移。
#
# Generated by SQLULDR
#
BASE_PATH=
TABLE_NAME=/ren
LOAD_DATA_INFILE=f:\soft\ren.csv
FORMAT = 0
gbloader命令行语法举例如下:
Load Records: 6001215
1 min 0.09 sec
指定用户名、口令和上面提到的控制文件路径就可实现数据批量导入。
一个令人疑惑的问题,就是我通过gbloader加载的数据,数据目录和原始文件排除分隔符占用的空间后大小几乎没有差别,也就是说压缩没有起作用。
2010/12/20 12:27 24,496,144 customer.tbl
2010/12/20 12:27 765,864,502 lineitem.tbl
2010/12/20 12:27 2,249 nation.tbl
2010/12/20 12:27 173,452,161 orders.tbl
2010/12/20 12:27 24,407,240 part.tbl
2010/12/20 12:27 119,784,616 partsupp.tbl
2010/12/20 12:27 394 region.tbl
2010/12/20 12:27 1,419,184 supplier.tbl
8 个文件 1,109,426,490 字节
F:\GBase\Server\data\tpch的大小920 MB (965,712,866 字节)
而用存储过程插入的数据,压缩率却比较高:
gbase> select count(*) from test.t;
+----------+
| count(*) |
+----------+
| 1000000 |
+----------+
1 row in set (0.00 sec)
gbase> select * from test.t into outfile 'f:/soft/t1m.csv';
Query OK, 1000000 rows affected, 1 warning (5.70 sec)
F:\GBase\Server\bin>dir \soft\t1m.csv
2011/01/09 19:04 16,764,132 t1m.csv
关于gbloader还有一些选项,比如压缩级别和并行度,我在测试中都没有生效,无论是直接在命令行指定还是在配置文件gbase_8a.ini中修改都无效,可能还有一些条件未满足,需要进一步研究。
三、数据加载和查询性能
对不大的数据量而言,比如TPC-H scale为1的大约1G字节数据,gbloader用时大约1分20秒,和Oracle sqlldr差不多,目前的性能表现已经可以接受了。
为了提供一个更有普遍价值的测试结果供用户在做数据库选型的参考,下面采用业界常用的数据仓库环境TPC-H测试,需要指出的是这并不是GBase官方的测试结果,只是我用TPC-H 2.8的数据结构和22个SQL查询表的结果。同时给出传统行存储方式的Oracle11.2的测试结果用于对比,SQL按照不同数据库的语法作了修改。脚本和数据生成器来自http://www.pilhokim.com/index.php?title=Project/EFIM/TPC-H。
表1 TPC-H 2.8 scale=1的测试对比,单位:秒
如上表所示,GBase在22个测试项目中有6项超过了Oracle,但有2个测试项目未执行成功。有3个项目执行时间远远长于Oracle,估计是GBase查询优化器的对某些复杂查询生成的执行计划不佳。当然,TPC-H给出的查询语句写法也未必是优化的,比如上述第20条在Oracle花费近7分钟,而做适当地等价改写后,执行时间就只有6.94秒,在此只是说明,要利用好GBase,数据库开发人员必须了解GBase的SQL执行特点,书写合适的语句。
四、结束语
看到这里,相信读者对已经有了初步的印象,在试用过程中,GBase 8a的表现稳定,没有出现服务器崩溃的现象,企业管理器对数据进行查询、更改也很直观方便,存储过程和函数的编辑器带有模板,对开发者增强了易用性。但是我们也看到这个数据库还有一些不成熟的地方。
第一、数据库功能缺失,比如由于它不支持主键,基于它的应用必须在数据库以外实现数据的唯一性。
第二、出错提示信息不够详细,中文化的程度不高。
第三、文档资料缺乏。(可能正式用户会有详细的资料)
第四、集成管理工具缺少备份功能和调试功能。有些模板例子不适用于GBase 8a。
国内企业在基础软件如操作系统和数据库管理系统方面与发达国家相比还有不少的差距,利用现有的自由/开源软件作为基础,在此之上开发是一个捷径,但是如果要真正在市场上占有一席之地,必须做好推广工作。以南大数据库为例,我们在其官方主页上找不到试用版软件下载,除了一篇不太详细的白皮书也找不到太多的技术资料,用户论坛注册页面也是空白的。在互联网上搜索,绝大多数结果都是千篇一律的新闻通稿,也找不到太多用户或开发者的技术文章,硕士论文倒有几篇,也需要账号才能访问。我的这个试用过程一波三折,前后耗费近1月,试想有多少最终用户有兴趣这么做呢。要是对某个产品一点都不了解,怎么会在采购时考虑呢。让更多的人了解和试用,是提高产品认可程度的必由之路,参考了其他软件不是什么严重的问题,连微软都无法避免学习其他公司的产品,如果有一日,我们能像Oracle和MySQL一样很容易获得软件和资料,以及众多开发者的技术分享,那就是国产数据库的成功之日,期待这日早点到来。