Java 애플리케이션에 내장할 수 있는 데이터 엔진은 풍부해 보이지만 사실 선택이 쉽지 않습니다. Redis는 컴퓨팅 성능이 좋지 않아 간단한 쿼리 시나리오에만 적합합니다. Spark 아키텍처는 복잡하고 무거워서 배포 및 유지 관리가 매우 까다롭습니다. H2HSQLDBDerby와 같은 임베디드 데이터베이스는 구조가 단순하지만 컴퓨팅 파워가 부족하고 기본적인 윈도우 기능도 지원하지 않는다.
반면, SQLite는 아키텍처와 컴퓨팅 성능에서 더 나은 균형을 이루었으며 널리 사용되는 Java 임베디드 데이터 엔진입니다.
SQLite는 간단한 구조를 가지고 있지만 핵심은 C 언어로 개발되었지만 Java 응용 프로그램에 쉽게 통합할 수 있는 작은 Jar 패키지로 잘 포장되어 외부에 표시됩니다. SQLite는 Java에서 호출할 수 있는 JDBC 인터페이스를 제공합니다.
Connection connection = DriverManager.getConnection("jdbc:sqlite::memory:"); Statement st = connection.createStatement(); st.execute("restore from d:/ex1"); ResultSet rs = st.executeQuery("SELECT * FROM orders");
SQLite는 표준 SQL 구문을 제공하며 일상적인 데이터 처리 및 계산에는 문제가 없습니다. 특히, SQLite는 이미 윈도우 기능을 지원해 그룹 내 많은 작업을 쉽게 구현할 수 있고, 다른 임베디드 데이터베이스보다 강력한 컴퓨팅 성능을 갖고 있다.
SELECT x, y, row_number() OVER (ORDER BY y) AS row_number FROM t0 ORDER BY x; SELECT a, b, group_concat(b, '.') OVER ( ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS group_concat FROM t1;
SQLite는 뛰어난 장점을 가지고 있지만 복잡한 애플리케이션 시나리오에 있어서는 여전히 몇 가지 단점이 있습니다.
Java 애플리케이션은 csv 파일, RDB, Excel, Restful과 같은 다양한 데이터 소스를 처리할 수 있지만 SQLite는 간단한 경우만 처리합니다. 즉, csv와 같은 텍스트 파일에 직접 사용 가능한 명령줄 로더를 제공합니다.
.import --csv --skip 1 --schema temp /Users/scudata/somedata.csv tab1
대부분의 다른 데이터 소스의 경우 SQLite는 편리한 인터페이스를 제공하지 않습니다. 코드를 직접 작성하여 데이터를 로드할 수 있으므로 전체 프로세스가 매우 번거롭고 시기적절합니다.
RDB 데이터 소스를 로드하는 방법은 먼저 Java를 사용하여 명령줄을 실행하고 RDB 라이브러리 테이블을 csv로 변환한 다음 JDBC를 사용하여 SQLite에 액세스하고 테이블 구조를 생성하는 것입니다. 명령줄을 실행하고 csv 파일을 가져옵니다. 마지막으로 새 테이블을 색인화하여 성능을 향상시킵니다. 이 방법은 테이블 구조와 테이블 이름을 유연하게 정의하거나 계산을 통해 로드된 데이터를 결정하려는 경우 코드 작성이 더 어렵습니다.
마찬가지로 다른 데이터 소스의 경우 SQLite를 직접 로드할 수 없고 지루한 변환 과정을 거쳐야 합니다.
SQL은 자연어에 가깝고 학습 임계값이 낮으며 간단한 계산을 구현하기 쉽지만 복잡한 집합 계산, 순서 계산, 결합 계산, 다단계 계산 등 복잡한 계산에는 좋지 않습니다. SQLite는 계산을 위해 SQL 문을 사용하며, 이러한 복잡한 계산을 간신히 구현하면 코드가 번거롭고 이해하기 어려워집니다.
예를 들어 특정 주식의 상승일수가 가장 긴 경우 SQL은 다음과 같이 작성해야 합니다.
select max(continuousDays)-1 from (select count(*) continuousDays from (select sum(changeSign) over(order by tradeDate) unRiseDays from (select tradeDate, case when price>lag(price) over(order by tradeDate) then 0 else 1 end changeSign from AAPL) ) group by unRiseDays)
이것은 SQLite만의 문제가 아닙니다. 객체 참조 등, 다른 SQL 데이터베이스 이러한 계산도 좋지 않습니다.
비즈니스 로직은 구조화된 데이터 계산과 프로세스 제어로 구성됩니다. SQLite는 SQL을 지원하고 구조화된 데이터 계산 기능을 가지고 있습니다. 그러나 SQLite는 저장 프로시저를 제공하지 않으며 독립적인 프로세스 제어 기능이 없으므로 일반적으로 사용할 수 없습니다. Java 메인 프로그램의 판단 및 루프 문입니다. Java에는 SQLite 데이터 테이블과 레코드를 전달하는 전문적인 구조화된 데이터 개체가 없기 때문에 변환 프로세스가 번거롭고 처리 프로세스가 원활하지 않으며 개발 효율성이 높지 않습니다.
앞서 언급했듯이 SQLite 커널은 Java 애플리케이션에 통합될 수 있지만 Java 기본 프로그램과 데이터를 교환하는 데는 시간이 많이 소요됩니다. 데이터의 크기가 크거나 상호 작용이 빈번하면 성능이 분명히 부족합니다. 또한 커널은 C 프로그램이기 때문에 SQLite는 Java 아키텍처의 일관성과 견고성을 어느 정도 파괴합니다.
Java 애플리케이션의 경우 기본적으로 JVM에 있는 esProc SPL이 더 나은 선택입니다.
esProc SPL은 JVM 기반의 오픈 소스 임베디드 데이터 엔진으로, JDBC 인터페이스를 통해 Java로 직접 통합 및 호출이 가능합니다. 후속 계산을 쉽게 수행할 수 있습니다.
SPL은 간단한 아키텍처를 가지며 독립적인 서비스가 필요하지 않습니다. SPL Jar 패키지만 도입하면 Java 환경에 배포할 수 있습니다.
데이터 소스를 직접 로드, 코드가 짧고 프로세스가 간단하며 적시성이 강합니다. 예를 들어 Oracle을 로드합니다.
a | |
1 | = Connect ("OrCl") |
2 | =a1.query@x("orderid, Client, Sellerid 선택) , OrderDate , OrderID별 주문 주문 금액") |
3 | >env(orders,A2) |
对于SQLite擅长加载的csv文件,SPL也可以直接加载,使用内置函数而不是外部命令行,稳定且效率高,代码更简短:
=T("/Users/scudata/somedata.csv")
多种外部数据源。除了RDB和csv,SPL还直接支持txt\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 | >env(orders,A4) |
JDBC接口可以方便地集成。加载的数据量一般比较大,通常在应用的初始阶段运行一次,只须将上面的加载过程存为SPL脚本文件,在Java中以存储过程的形式引用脚本文件名:
Class.forName("com.esproc.jdbc.InternalDriver"); Connection conn =DriverManager.getConnection("jdbc:esproc:local://"); CallableStatement statement = conn.prepareCall("{call init()}"); statement.execute();
SPL的计算能力更强大
SPL提供了丰富的计算函数,可以轻松实现日常计算。SPL支持多种高级语法,大量的日期函数和字符串函数,很多用SQL难以表达的计算,用SPL都可以轻松实现,包括复杂的有序计算、集合计算、分步计算、关联计算,以及带流程控制的业务逻辑。
丰富的计算函数。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) | //关联 |
标准SQL语法。SPL也提供了SQL-92标准的语法,比如分组汇总:
$select year(OrderDate) y,month(OrderDate) m, sum(Amount) s,count(1) c from {Orders} Where Amount>=? and Amount<? ;arg1,arg2
函数选项、层次参数等方便的语法。功能相似的函数可以共用一个函数名,只用函数选项区分差别,比SQL更加灵活方便。比如select函数的基本功能是过滤,如果只过滤出符合条件的第1条记录,可使用选项@1:
T.select@1(Amount>1000)
二分法排序,即对有序数据用二分法进行快速过滤,使用@b:
T.select@b(Amount>1000)
有序分组,即对分组字段有序的数据,将相邻且字段值相同的记录分为一组,使用@b:
T.groups@b(Client;sum(Amount))
函数选项还可以组合搭配,比如:
Orders.select@1b(Amount>1000)
结构化运算函数的参数有些很复杂,比如SQL就需要用各种关键字把一条语句的参数分隔成多个组,但这会动用很多关键字,也使语句结构不统一。SPL使用层次参数简化了复杂参数的表达,即通过分号、逗号、冒号自高而低将参数分为三层:
join(Orders:o,SellerId ; Employees:e,EId)
更丰富的日期和字符串函数。除了常见函数,比如日期增减、截取字符串,SPL还提供了更丰富的日期和字符串函数,在数量和功能上远远超过了SQL,同样运算时代码更短。比如:
季度增减:elapse@q(“2020-02-27”,-3) //返回2019-05-27
N个工作日之后的日期:workday(date(“2022-01-01”),25) //返回2022-02-04
字符串类函数,判断是否全为数字:isdigit(“12345”) //返回true
取子串前面的字符串:substr@l(“abCDcdef”,“cd”) //返回abCD
按竖线拆成字符串数组:“aa|bb|cc”.split(“|”) //返回[“aa”,“bb”,“cc”]
SPL还支持年份增减、求季度、按正则表达式拆分字符串、拆出SQL的where或select部分、拆出单词、按标记拆HTML等大量函数。
简化有序运算。涉及跨行的有序运算,通常都有一定的难度,比如比上期和同期比。SPL使用"字段[相对位置]"引用跨行的数据,可显著简化代码,还可以自动处理数组越界等特殊情况,比SQL窗口函数更加方便。比如,追加一个计算列rate,计算每条订单的金额增长率:
=T.derive(AMOUNT/AMOUNT[-1]-1: rate)
综合运用位置表达式和有序函数,很多SQL难以实现的有序运算,都可以用SPL轻松解决。比如,根据考勤表,找出连续 4 周每天均出勤达 7 小时的学生:
A | |
1 | =Student.select(DURATION>=7).derive(pdate@w(ATTDATE):w) |
2 | =A1.group@o(SID;~.groups@o(W;count(~):CNT).select(CNT==7).group@i(W-W[-1]!=7).max(~.len()):weeks) |
3 | =A2.select(weeks>=4).(SID) |
简化集合运算,SPL的集合化更加彻底,配合灵活的语法和强大的集合函数,可大幅简化复杂的集合计算。比如,在各部门找出比本部门平均年龄小的员工:
A | |
1 | =Employees.group(DEPT; (a=~.avg(age(BIRTHDAY)),~.select(age(BIRTHDAY) |
2 | =A1.conj(YOUNG) |
计算某支股票最长的连续上涨天数:
A | |
1 | =a=0,AAPL.max(a=if(price>price[-1],a+1,0)) |
简化关联计算。SPL支持对象引用的形式表达关联,可以通过点号直观地访问关联表,避免使用JOIN导致的混乱繁琐,尤其适合复杂的多层关联和自关联。比如,根据员工表计算女经理的男员工:
=employees.select(gender:"male",dept.manager.gender:"female")
方便的分步计算,SPL集合化更加彻底,可以用变量方便地表达集合,适合多步骤计算,SQL要用嵌套表达的运算,用SPL可以更轻松实现。比如,找出销售额累计占到一半的前n个大客户,并按销售额从大到小排序:
A | B | |
2 | =sales.sort(amount:-1) | /销售额逆序排序,可在SQL中完成 |
3 | =A2.cumulate(amount) | /计算累计序列 |
4 | =A3.m(-1)/2 | /最后的累计即总额 |
5 | =A3.pselect(~>=A4) | /超过一半的位置 |
6 | =A2(to(A5)) | /按位置取值 |
流程控制语法。SPL提供了流程控制语句,配合内置的结构化数据对象,可以方便地实现各类业务逻辑。
分支判断语句:
A | B | |
2 | … | |
3 | if T.AMOUNT>10000 | =T.BONUS=T.AMOUNT*0.05 |
4 | else if T.AMOUNT>=5000 && T.AMOUNT<10000 | =T.BONUS=T.AMOUNT*0.03 |
5 | else if T.AMOUNT>=2000 && T.AMOUNT<5000 | =T.BONUS=T.AMOUNT*0.02 |
循环语句:
A | B | |
1 | =db=connect("db") | |
2 | =T=db.query@x("select * from sales where SellerID=? order by OrderDate",9) | |
3 | for T | =A3.BONUS=A3.BONUS+A3.AMOUNT*0.01 |
4 | =A3.CLIENT=CONCAT(LEFT(A3.CLIENT,4), " co.,ltd.") | |
5 | … |
与Java的循环类似,SPL还可用break关键字跳出(中断)当前循环体,或用next关键字跳过(忽略)本轮循环,不展开说了。
计算性能更好。在内存计算方面,除了常规的主键和索引外,SPL还提供了很多高性能的数据结构和算法支持,比大多数使用SQL的内存数据库性能好得多,且占用内存更少,比如预关联技术、并行计算、指针式复用。
SPL支持JDBC接口,代码可外置于Java,耦合性更低,也可内置于Java,调用更简单。SPL支持解释执行和热切换,代码方便移植和管理运营,支持内外存混合计算。
外置代码耦合性低。SPL代码可外置于Java,通过文件名被调用,既不依赖数据库,也不依赖Java,业务逻辑和前端代码天然解耦。
对于较短的计算,也可以像SQLite那样合并成一句,写在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是基于Java的解释型语言,无须编译就能执行,脚本修改后立即生效,支持不停机的热切换,适合应对变化的业务逻辑。
方便代码移植。SPL通过数据源名从数据库取数,如果需要移植,只要改动配置文件中的数据源配置信息,而不必修改SPL代码。SPL支持动态数据源,可通过参数或宏切换不同的数据库,从而进行更方便的移植。为了进一步增强可移植性,SPL还提供了与具体数据库无关的标准SQL语法,使用sqltranslate函数可将标准SQL转为主流方言SQL,仍然通过query函数执行。
方便管理运营。由于支持库外计算,代码可被第三方工具管理,方便团队协作;SPL脚本可以按文件目录进行存放,方便灵活,管理成本低;SPL对数据库的权限要求类似Java,不影响数据安全。
内外存混合计算。有些数据太大,无法放入内存,但又要与内存表共同计算,这种情况可利用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) |
SQLite使用简单方便,但数据源加载繁琐,计算能力不足。SPL架构也非常简单,并直接支持更多数据源。SPL计算能力强大,提供了丰富的计算函数,可以轻松实现SQL不擅长的复杂计算。SPL还提供多种优化体系结构的手段,代码既可外置也可内置于Java,支持解释执行和热切换,方便移植和管理运营,并支持内外存混合计算。
위 내용은 SQLite에서 SPL 예제 분석까지 Java 임베디드 데이터 엔진의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!