有什么简单轻量的内存数据库技术

HANA/SPARK/Redis都是常见的内存数据库,但架构复杂沉重,很多场景并不适用。提到简单轻量的内存数据技术,SQLite是比较常见的,优点是体积轻巧,架构简单,可直接嵌入JAVA代码。SQLite的缺点是缺乏独立服务,不适合追求稳定的应用环境,不支持存储过程,计算能力不强,而且速度也比较慢,使用外部数据必须经过繁琐的入库过程。

简单轻量的内存数据库技术,集算器SPL比SQLite好用多了。

SPL是开源的JAVA计算类库,架构简单且灵活,不仅可以直接嵌入JAVA代码,也支持独立服务。SPL有多种性能优化手段,有强大的计算能力,可直接使用外部数据。

 

SPL架构简单,无须独立服务,只要引入SPL的Jar包,就可以嵌入JAVA代码进行计算。先把外存数据加载到内存,比如从Oracle加载:

A
1 =connect("orcl")
2 =A1.cursor@x("select   OrderID,Client,SellerID,OrderDate,Amount from orders order by OrderID")
3 =A2.memory(OrderID).index()
4 >env(orders,A3)

加载之后,就可以用SPL简单直观的语法进行计算内存。

A
1 =Orders.select(Amount>=arg1   && Amount<arg2)
2 =A1.groups(year(OrderDate):y,month(OrderDate):m;   sum(Amount):s,count(1):c)

SPL提供了JDBC接口,可以被JAVA方便地集成。加载的数据量一般比较大,通常在应用的初始阶段运行一次,只须将上面的加载过程存为SPL脚本文件,在JAVA中以存储过程的形式引用脚本文件名:

…
Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
CallableStatement statement = conn.prepareCall("{call init()}");
statement.execute();
...

内存计算通常要反复执行,并发也大。较长的计算适合外置的脚本文件,修改后无须编译。对于较短的计算,可以像SQL语句那样合并成一句,写在JAVA代码中:

…
Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = conn.createStatement();
String arg1="1000";
String arg2="2000"
ResultSet result = statement.executeQuery(=Orders.select(Amount>="+arg1+" && Amount<"+arg2+"). groups(year(OrderDate):y,month(OrderDate):m; sum(Amount):s,count(1):c)");
...

SPL提供了丰富的计算函数,可以轻松实现内存计算,下面是一些例子:

A B
1 =Orders.find(arg_OrderIDList) //多键值查找
2 =Orders.select(Amount>1000   && like(Client,\"*S*\")) //模糊查询
3 = Orders.sort(Client,-Amount) //排序
4 = Orders.id(Client) //去重
5 =join(Orders:O,SellerId;   Employees:E,EId)
.new(O.OrderID, O.Client,O.Amount,E.Name,E.Gender,E.Dept)
//关联

SPL还支持标准SQL语法,包括丰富的字符串函数和日期函数,还支持关联计算、集合计算、子查询。比如,前面的计算可以改写为下面的SQL:

$select year(OrderDate) y,month(OrderDate) m, sum(Amount) s,count(1) c
from {Orders}
Where Amount>=? and Amount<? ;arg1,arg2

 

SPL架构灵活,不仅支持嵌入计算,也支持独立服务,适合对稳定性要求严格的应用。值得一提的是,计算代码和集成方式无需改变,只要注明“服务端执行”:

…
Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://onlyServer=true");
Statement statement = conn.createStatement();
String arg1="1000";
String arg2="2000"
ResultSet result = statement.executeQuery(=Orders.select@m(Amount>="+arg1+" && Amount<"+arg2+"). gr也oups(year(OrderDate):y,month(OrderDate):m; sum(Amount):s,count(1):c)");
...

 

SPL计算能力强大,可简化分步计算、有序计算、分组后计算等逻辑较复杂的计算,SQL和存储过程难以实现的计算,用SPL解决起来就很轻松。比如,找出销售额累计占到一半的前n个大客户,并按销售额从大到小排序:

A B
2 =sales.sort(amount:-1) /销售额逆序排序
3 =A2.cumulate(amount) /计算累计序列
4 =A3.m(-1)/2 /最后的累计即总额
5 =A3.pselect(~>=A4) /超过一半的位置
6 =A2(to(A5)) /按位置取值

 

在内存计算方面,除了常规的主键和索引外,SPL还提供了很多高性能的数据结构和算法支持,比大多数使用SQL的内存数据库性能好得多,且占用内存更少。需要HANA/Spark集群才能完成的运算,在SPL中常常用单机就解决了。

SPL支持并行计算,只须对原代码进行简单修改,就可以利用多核CPU提升性能。比如:

A
1 =Orders.select@m(Amount>=arg1 && Amount<arg2)
2 =A1.groups(year(OrderDate):y,month(OrderDate):m;   sum(Amount):s,count(1):c)

SPL支持指针式复用,可以节省内存。SPL的数据以指针的形式参与计算,多步骤算法和不同的算法只是复用同一个表,而不像SQL那样每次都要复制记录。

SPL支持预关联技术,可以提升计算性能。SQL只能用复制记录的方式实现关联,会占用大量内存,SPL支持指针式复用,加载阶段的预关联几乎不占内存。内存计算时,可以用"."引用关联字段,更加直观方便:

=callRecord.sum(OUTID.BRANCHID.OUTCOST+INID.BRANCHID.INCOST+OUTID.AGENTID.OUTCOST+INID.AGENTID.INCOST)

SPL还支持内存压缩,允许将更多的数据加载到内存,且计算代码无须修改。

 

SPL支持多种外部数据源,可避免入库或格式转换的麻烦。除了关系型数据库,还包括txt\csv\xls等文件,MongoDB、Hadoop、redis、ElasticSearch、Kafka、Cassandra等NoSQL,以及WebService XML、Restful Json等多层数据。比如,将HDSF里的文件加载到内存:

A
1 =hdfs_open(;"hdfs://192.168.0.8:9000")
2 =hdfs_file(A1,"/user/Orders.csv":"GBK")
3 =A2.cursor@t()
4 =hdfs_close(A1)
5 =A3.memory(OrderID).index()
6 >env(orders,A5)

SPL支持内外存混合计算。有些数据太大,无法放入内存,但又要与内存表共同计算,这种情况可利用SPL实现内外存混合计算。比如,主表orders已加载到内存,大明细表orderdetail是文本文件,下面进行主表和明细表的关联计算:

A
1 =file("orderdetail.txt").cursor@t()
2 =orders.cursor()
3 =join(A1:detail,orderid   ; A2:main,orderid)
4 =A3.groups(year(main.orderdate):y;   sum(detail.amount):s)