一個比 SQLite 還好用的資料庫神器

来源:https://www.cnblogs.com/88223100/archive/2023/06/25/A-database-artifact-that-works-better-than-SQLite.html
-Advertisement-
Play Games

很多小微型應用程式也需要一些數據處理和計算能力,如果集成一個資料庫就顯得太沉重了,這種情況下 SQLite 是一個不錯的選擇,它架構簡單,集成方便,可持久化存儲數據,並提供 SQL 實現計算能力。 但是,對於某些較複雜的場景,SQLite 仍有不足之處。 ...


很多小微型應用程式也需要一些數據處理和計算能力,如果集成一個資料庫就顯得太沉重了,這種情況下 SQLite 是一個不錯的選擇,它架構簡單,集成方便,可持久化存儲數據,並提供 SQL 實現計算能力。
但是,對於某些較複雜的場景,SQLite 仍有不足之處。
SQLite 面對複雜場景的不足

數據源支持

SQLite 像個資料庫,可以對自有的庫文件提供較好的支持,但應用程式有時還要處理其它形式的數據,比如文本文件、Excel、其它資料庫、Restful 等 Web 上的數據。SQLite 只支持 csv 文件的讀取,不支持其他數據源,除非硬編碼。而且,SQLite 雖然支持 csv 文件,但使用過程很繁瑣,需要先用命令行創建資料庫,再用 create 命令創建表結構,然後用 import 命令導入數據,最後才能用 SQL 查詢數據。
除了常規結構化數據,現代應用還會經常碰到 Json,XML 等複雜格式的數據。SQLite 有計算 Json 串的能力,但不支持直接讀取多層數據源,包括 Json 文件 /RESTful,需要硬寫代碼,或再藉助第三方類庫,拼成 insert 語句插入數據表,代碼很繁瑣。SQLite 也不能計算 XML 串,更不能讀取 XML 文件 /WebService。
應用程式有時需要把數據寫成格式通用的文件,以便輸出、轉移或交換,有時候還要把數據主動寫入其他數據源。但 SQLite 只能將數據持久化到自有的庫文件,不能直接寫入外部數據源,包括基本的 csv 文件。

複雜計算

SQLite 採用 SQL 語句做計算,SQL 的優點和缺點都會繼承下來。SQL 接近自然語言,學習門檻低,容易實現簡單的計算,但不擅長複雜的計算,經常會造成代碼會繁瑣難懂。
即使一些不太複雜的計算,SQL 實現起來也不容易。比如,計算每個客戶銷售額最大的 3 筆訂單:
select * from (select *, row_number() over (partition by Client order by Amount desc) as row_number from Orders) where row_number<=3
這個例子要計算組內的前 N 條記錄,需要用視窗函數生成組內的序號偽列,再過濾偽列,代碼因而顯得複雜。
複雜些的計算,SQL 代碼更加冗長難懂。比如,某支股票的最大連續上漲天數:

select max(continuousdays)
from (
    select count(*) continuousdays
    from (
        select sum(risingflag) over (order by day) norisingdays
        from (
           select day, case when price>lag(price) over (order by day) then 0 else 1 end risingflag 
           from tbl
        )
    ) group by norisingdays
)

SQL 很難直接表達連續上漲的概念,只能換個方法變相實現,即通過累計不漲天數來計算連續上漲天數,這種方法技巧性強,編寫難度大且不易理解。而且 SQL 難以調試,導致維護困難。

再看個例子:找出銷售額占到一半的前 n 個客戶,並按銷售額從大到小排序。

with A as
    (select client,amount,row_number() over (order by amount) ranknumber
    from sales)
select client,amount
from (select client,amount,sum(amount) over (order by ranknumber) acc
     from A)
where acc>(select sum(amount)/2 from sales)
order by amount des

SQL 很難處理恰好要過線的客戶,只能換個方法變相實現,即計算銷售額從小到大的累計值,反過來找出累計值不在後一半的客戶。這種方法技巧性強,代碼冗長,而且難以調試。

除此之外,SQLite 的日期和字元串函數也不夠豐富,比如缺乏季度增減、工作日計算等,這些缺點限制了 SQLite,不適合計算需求較複雜的場景。

流程處理

SQL 本身缺乏流程處理能力,資料庫會藉助存儲過程實現完整的業務邏輯,但 SQLite 不支持存儲過程,也就無法直接實現完整的業務邏輯,只能藉助主應用的能力,將 SQL 數據對象轉為應用中的數據對象(比如 Java 的 resultSet/List<EntityBean> 等對象),再用主程式的 for/if 等語句處理流程,最後再轉回 SQL 的數據對象,代碼非常繁瑣。複雜的業務邏輯要在 SQL 對象和主應用的對象之間轉換多次,更加麻煩,這裡就不展示了。
esProc SPL 解決 SQLite 困難
如果要為 Java 小微型應用提供數據處理和計算能力,還有一個更好的選擇:esProc SPL。
esProc SPL 一個開源的數據處理引擎,架構簡單,集成方便,可持久化存儲數據,有足夠的計算能力,這些特點與 SQLite 類似。
SPL 架構簡單,不用配置服務、節點、集群,只要引入 SPL 的 Jar 包,就可以部署在 Java 環境中。
SPL 提供了 JDBC 介面,可以方便地集成到 Java 應用中,簡單的查詢類似 SQL。
GitHub:https://github.com/SPLWare/esProc
圖片

 


Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = conn.createStatement();
ResultSet result = statement.executeQuery("=T(\"D:/Orders.csv\").select(Amount>1000 && like(Client,\"*s*\"))");

SPL 支持數據持久化,可以將數據保存到自有數據格式(集文件)中,比如批量新增記錄:

  A
1 =create(OrderID,Client,SellerID,Amount,OrderDate)
2

=A1.record([201,"HDR",9,2100.0,date("2021-01-01"),
202,"IBM",9,1900,date("2021-01-02"),

203,"APPLE",4,1900,date("2021-01-03")])

3 =file("d:/Orders.btx").export@ab(A2)
上面 A3 代碼 export@ab,@a 表示追加,@b 表示集文件格式

除了直接持久化,也可以先處理記憶體中的序表(SPL 的結構化數據對象,可類比為 SQL 結果集),再將序表覆蓋寫入集文件,具體做法是將 export@ab 改為 export@b。這種方式性能不如 SQLite,但小微型應用的數據量普遍不大,覆寫的速度通常可接受。

組表是 SPL 的另一種自有數據格式,支持高性能批量增刪改,適用於大數據量高性能計算(這不是本文重點)。

除了自有格式,SPL 也可以將數據保存到 csv 文件中,只要把 A3 改為:

file("d:/Orders.csv").export@tc(A2)

SPL 有足夠的計算能力,支持各類 SQL 式計算,包括分組後計算(視窗函數):

  A B
1 =Orders.new(Client,Amount) // 選出部分欄位
2 =Orders.select(Amount>1000 && like(Client,\"*s*\")) // 模糊查詢
3 = Orders.sort(Client,-Amount) // 排序
4 = Orders.id(Client) // 去重
5 =Orders.groups(year(OrderDate):y,Client;sum(Amount):amt).select(amt>3000) // 分組彙總
6 =[Orders.select(Amount>3000),A1.select(year(OrderDate)==2009)].union() // 並集
7 =Orders.groups(year(OrderDate):y,Client;sum(Amount):amt).select(like(Client,\"*s*\")) // 子查詢
8 =A5.derive(amt/amt[-1]-1: rate) // 跨行

SPL 提供了基本的 SQL 語法,比如分組彙總:

$select year(OrderDate) y,month(OrderDate) m, sum(Amount) s,count(1) c from {Orders} Where Amount>=? and Amount<? ;arg1,arg2
除了這些基礎能力外,SPL 還能剋服了 SQLite 的各種不足,全面支持各類數據源,具有更強的計算能力,流程處理方便,可以面對更複雜的應用場景。

數據源支持

SPL 讀取 csv 文件只需一步,在 Java 里嵌入下麵的 SPL 代碼:T("d:/Orders.csv").select(Amount>2000 && Amount<=3000)

函數 T 不僅可以讀取集文件,也可以讀取 csv 文件,並生成序表。SPL 導入數據時,數據類型會自動解析,不必手工指定。整個過程無需多餘編碼,比 SQLite 方便多了。
如果 csv 格式不規範,還可以使用 import 函數指定分隔符、欄位類型、跳過行數,並處理轉義符、引號、括弧等,比 SQLite 提供的功能豐富多了。
SPL 內置多種數據源介面,包括 tsv、xls、Json、XML、RESTful、WebService,以及其他資料庫,甚至支持 Elasticsearch、MongoDB 等特殊數據源。
這些數據源都可以直接使用,非常方便。對於其他未列入的數據源,SPL 也提供了介面規範,只要按規範輸出為 SPL 的結構化數據對象,就可以進行後續計算。
SPL 可直接解析多層數據源。讀取並計算 Json 文件:
json(file("d:/xml/emp_orders.json").read()).select(Amount>2000 && Amount<=3000)
json(httpfile("http://127.0.0.1:6868/api/orders").read()).select(Amount>2000 && Amount<=3000)

XML 文件:

  A
1 =file("d:/xml/emp_orders.xml").read()
2 =xml(A1,"xml/row")
3 =A2.select(Amount>1000 && Amount<=2000 && like@c(Client,"*business*"))
WebService:
  A
1 =ws_client("http://127.0.0.1:6868/ws/RQWebService.asmx?wsdl")
2 =ws_call(A1,"RQWebService":"RQWebServiceSoap":"getEmp_orders")
3 =A2.select(Amount>1000 && Amount<=2000 && like@c(Client,"*business*"))
SPL 序表支持多層結構數據,比 SQL 庫表的二維結構更容易表達 Json/XML,計算代碼也更簡單。這部分內容不是本文重點,就此略過。

跨源計算

SPL 開放性較好,可以直接計算多種數據源,這些數據源可以和 SPL 集文件進行跨源計算。比如,對集文件和 csv 進行內關聯分組彙總:

join(T("d:/Orders.btx"):o,SellerId; T("d:/Emp.csv"):e,EId).groups(e.Dept;sum(o.Amont))

外部數據源之間也可以方便地進行跨源計算。比如 csv 和 RESTful 左關聯:

join@1(json(httpfile("http://127.0.0.1:6868/api/orders").read()):o,SellerId; T("d:/Emp.csv"):e,EId)

寫成多步驟的形式更易讀:
  A
1 =Orders=json(httpfile("http://127.0.0.1:6868/api/orders").read())
2 =Employees=T("d:/Emp.csv")
3 =join@1(Orders:o,SellerId;Employees:e,EId)
只用 SPL 語言就可以實現跨源計算,不必藉助 Java 或命令行,代碼簡短易懂,比 SQL 的開發效率高得多。

任意數據源的持久化

SPL 除了支持自有數據格式的持久化,也支持其他數據源,同樣是通過序表為媒介。比如:

file("d:/Orders.csv").export@t(A2)          //csv文件
file("d:/Orders.xlsx").xlsexport@t(A2)      //xls文件
file("d:/Orders.json").write(json(A2))      //json文件
特別地,SPL 支持任意資料庫的持久化,以 Oracle 為例:
  A B
1 =connect("orcl") / 連接外部 oracle
2 =T=A1.query("select * from salesR where SellerID=?",10) / 批量查詢,序表 T
3 =NT=T.derive() / 複製出新序表 NT
4 =NT.field("SELLERID",9) / 批量修改新序表
5 =A1.update(NT:T,sales;ORDERID) / 持久化

資料庫的持久化以序表為媒介,其優點相當明顯:函數 update 可自動比對修改(增改刪)前後的序表,能夠方便地實現批量數據地持久化。

計算能力

SPL 支持有序計算、集合計算、分步計算、關聯計算,可以簡化複雜的結構化數據計算。
簡單的比如,計算每個客戶銷售額最大的 3 筆訂單:

Orders.group(Client).(~.top(3;Amount))

SPL 代碼很直觀,先按 Client 分組,再對各組(即符號~)計算 TopN。SPL 之所以代碼簡單,錶面上是因為 SQL 沒有 top 函數而 SPL 直接提供了,本質是因為 SPL 有真正的行號欄位,或者說,SPL 支持有序集合。SPL 代碼簡單,還因為集合化更加徹底,可以實現真正的分組,即只分組不彙總,這就可以直觀地計算組內數據。
複雜些的計算,SPL 實現起來也不難最大連續上漲天數:
  A
1 =tbl.sort(day)
2 =t=0,A1.max(t=if(price>price[-1],t+1,0))
SPL 容易表達連續上漲的概念,先按日期排序;再遍歷記錄,發現上漲則計數器加 1。這裡既用到了迴圈函數 max,也用到了有序集合,代碼中 [-1] 表示上一條,是相對位置的表示方法,price [-1] 表示上一個交易日的股價,比整體移行(lag 函數)更直觀。

再看個例子,求銷售額占到一半的前 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 集合化成更徹底,可以用變數方便地表達集合,併在下一步用變數引用集合繼續計算,因此特別適合多步驟計算。將大問題分解為多個小步驟,可以方便地實現複雜的計算目標,代碼不僅簡短,而且易於理解。此外,多步驟計算天然支持調試,無形中提高了開發效率。

上面例子使用了有序計算、集合計算、分步計算,SPL 從簡單到複雜的計算都可以很好的完成。此外,SPL 還支持游離記錄,可以用點號直觀地引用關聯表,從而簡化複雜的關聯計算。
SPL 還提供了更豐富的日期和字元串函數,在數量和功能上遠遠超過傳統資料庫。
值得一提的是,為了進一步提高開發效率,SPL 還創造了獨特的函數語法。

流程處理

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  

上述代碼之外,SPL 還有更多針對結構化數據的流程處理功能,可進一步提高開發效率,比如:每輪迴圈取一批而不是一條記錄;某欄位值變化時迴圈一輪。

上面的業務邏輯可保存為腳本文件,並置於應用程式外,以存儲過程的形式被調用:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
CallableStatement statement = conn.prepareCall("{call queryOrders()}");
statement.execute();
SPL 是解釋型代碼,修改後不必編譯就可直接運行,也不必重啟應用,可有效降低維護成本。外置的 SPL 腳本不僅可以有效降低系統耦合性,還具有熱切換的特點。SQLite 不支持存儲過程,也就不能將業務邏輯外置於主應用,耦合性高,應用結構差。
SPL 在 Java 下明顯優於 SQLite,但對於非 Java 應用就會麻煩一點了,只能使用獨立的 ODBC 服務或 HTTP 服務的方式,架構不夠輕便,集成性也下降了。需要註意的是,android 屬於 Java 體系,SPL 可以正常運行,但 iOS 目前還沒有較成熟的 JVM 環境,SPL 就無法支持了。

GitHub:https://github.com/SPLWare/esProc

 

作者|GitHubDaily

本文來自博客園,作者:古道輕風,轉載請註明原文鏈接:https://www.cnblogs.com/88223100/p/A-database-artifact-that-works-better-than-SQLite.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大家好,我是沙漠盡頭的狼。 網站使用Blazor重構上線一天了,用Blazor開發是真便捷,空閑時間查查gpt和github,又上線一個 [正則表達式線上驗證工具](https://dotnet9.com/tools/regextester) 和幾個線上小游戲,比如 [井字棋游戲](https:// ...
  • 在`WPF`中,命令是一種用於處理用戶交互操作的機制。它將操作行為與界面元素解耦,使得界面元素可以通過命令進行觸發和執行相應的邏輯。`WPF`中的命令模型通過`ICommand`介面和相關的實現類來實現。命令模式的設計思想是將命令的發送者(例如按鈕)與命令的執行者(例如視圖模型中的方法)解耦,使得它... ...
  • 問題應該算挺常見的但是一句話還挺難說清楚,所以百度特別難搜。 場景就是,有一堆以員工名稱命名的文件(名稱可能還有字母數字等前尾碼),現在給定一個員工清單,需要從這些文件中篩選出員工清單上列出的員工的文件,並複製到另外一個目錄中。 輸入: 1. 許多文件名包含員工名稱的文件 2.一個清單文件,裡面包含 ...
  • 哈嘍大家好,我是鹹魚 今天跟大家分享一個關於 zabbix Timeout 值設置不當導致的問題,這個問題不知道大家有沒有碰到過 ## 問題 事情經過是這樣的: 把某一臺 zabbix agent 的模板由原來的 `Template OS Windows by Zabbix agent` 換成了 ` ...
  • # Spark Spark是一種快速、通用、可擴展的大數據分析引擎,2009年誕生於加州大學伯克利分校AMPLab,2010年開源,2013年6月成為Apache孵化項目,2014年2月成為Apache的頂級項目,2014年5月發佈spark1.0,2016年7月發佈spark2.0,2020年6月 ...
  • ![file](https://img2023.cnblogs.com/other/3195851/202306/3195851-20230625185718639-2144905227.jpg) > 近日,Apache SeaTunnel 正式發佈 2.3.2 版本。此時距離上一版本 2.3.1 ...
  • 摘要:本文將介紹如何在 Docker 環境下搭建 MS SQL Server 的主從同步,幫助讀者瞭解主從同步的原理和實現方式,進而提高數據的可靠性和穩定性。 一、前言 在當今信息化的時代,數據的安全性和穩定性顯得尤為重要。資料庫是許多企業和組織存儲和管理數據的核心,因此如何保證資料庫的高可用性和數 ...
  • ## case1(表鎖的讀-寫-讀阻塞) 上篇文檔中提到過 >WRITE locks normally have higher priority than READ locks to ensure that updates are processed as soon as possible. Thi ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...