一、cstore_fdw的简介
https://github.com/citusdata/cstore_fdw,此外部表扩展是由citusdata公司开发,使用orc_file格式对数据进行列式存储。
优点1:因为有压缩,所以在disk上的存储大大减少,压缩比能达到2-4倍
优点2:数据内部分块存储,对于块数据进行了max以及min值的记录,在查询时能够进行跳块查询
优点3:在进行查询时,并不是将所有的磁盘数据都load到内存,而是选择列根据记录的skiplist中的offset来load所需要的数据,减少IO
二、安装使用
[[email protected] ~]# git clone https://github.com/citusdata/cstore_fdw.git
下载好后修改Makefile文件中的pgconfig指定到安装目录下 例如:/usr/local/postgres/bin/pgconfig
[[email protected] ~]# make && make install
配置postgres.conf文件末尾添加:
shared_preload_libraries = ‘cstore_fdw‘
启动数据库:
[[email protected] ~]$ pg_ctl -D db1 -l logfile start -m fast
[[email protected] ~]$ psql
postgres=# create extension cstore_fdw; CREATE EXTENSION postgres=# create server cstore_server foreign data wrapper cstore_fdw ; CREATE SERVER postgres=# CREATE FOREIGN TABLE customer_reviews postgres-# ( postgres(# customer_id TEXT, postgres(# review_date DATE, postgres(# review_rating INTEGER, postgres(# review_votes INTEGER, postgres(# review_helpful_votes INTEGER, postgres(# product_id CHAR(10), postgres(# product_title TEXT, postgres(# product_sales_rank BIGINT, postgres(# product_group TEXT, postgres(# product_category TEXT, postgres(# product_subcategory TEXT postgres(# ) postgres-# SERVER cstore_server postgres-# OPTIONS(compression ‘pglz‘);
PG原生表占用磁盘大小:
postgres=# insert into customer_reviews select * from customer; INSERT 0 176774 postgres=# select pg_relation_size(‘customer‘); pg_relation_size ------------------ 145489920 (1 row)
经过cstore_fdw外部扩展压缩后占用的磁盘大小:
[[email protected] 13056]$ ll /home/postgres/db1/cstore_fdw/13056
-rw------- 1 postgres postgres 6236569 Dec 5 10:07 278237
-rw------- 1 postgres postgres 56 Dec 5 10:07 278237.footer
对比后磁盘使用减少了很多!!
三、源码分析
postgres中外部表的实现相当于一个引擎,通过挂接C语言的函数指针实现
Datum cstore_fdw_handler(PG_FUNCTION_ARGS) { FdwRoutine *fdwRoutine = makeNode(FdwRoutine); fdwRoutine->GetForeignRelSize = CStoreGetForeignRelSize; fdwRoutine->GetForeignPaths = CStoreGetForeignPaths; fdwRoutine->GetForeignPlan = CStoreGetForeignPlan; fdwRoutine->ExplainForeignScan = CStoreExplainForeignScan; fdwRoutine->BeginForeignScan = CStoreBeginForeignScan;//1 fdwRoutine->IterateForeignScan = CStoreIterateForeignScan;//2 fdwRoutine->ReScanForeignScan = CStoreReScanForeignScan;//3 fdwRoutine->EndForeignScan = CStoreEndForeignScan;//4 fdwRoutine->AnalyzeForeignTable = CStoreAnalyzeForeignTable; fdwRoutine->PlanForeignModify = CStorePlanForeignModify;//5 fdwRoutine->BeginForeignModify = CStoreBeginForeignModify;//6 fdwRoutine->ExecForeignInsert = CStoreExecForeignInsert;//7 fdwRoutine->EndForeignModify = CStoreEndForeignModify;//8 PG_RETURN_POINTER(fdwRoutine); }
1、2、3、4构成了查询操作 例如: select * from customer_reviews;
5、6、7、8构成了插入操作 例如:insert into customer_reviews select * from customer;
特别注意的是在插入的时候,由于CStorePlanForeignModify这个函数中判断了tableEntry->rtekind == RTE_SUBQUERY,
因此 insert into xx values xxx 这种插入是不支持的。
从源码中观察到在CStoreEndForeignModify中会进行flushstripe操作,就是不管插入一条数据还是批量插入数据,都会进行flushstripe操作
如果插入一条数据,则此条数据占用了一个条带的磁盘空间
如果是批量插入,则按照默认的条带大小,块大小来进行分割,满足stripe了就刷磁盘,接着剩余不满足stripe的作为另外一个条带,如果按照一条数据一个条带的话,查询load数据就会相当缓慢。
最后得出结论:对于总是进行单条插入或者交易型数据库,这种压缩效率就不是很明显了,如果对于批量插入的话,压缩比例还是很可观的,而且查询也会较快。
RCFile格式对比orc格式:
还有就是对于RCfile这种格式,字符串类型的压缩并没有很明显的处理,不像orc格式,orc带有字典压缩处理,而RCFile并没有
https://github.com/gokhankici/orc_fdw
这个外部表扩展仅仅对orc格式的文件进行读操作,并没有写操作,写文件的操作是使用java语言开发的。