DuckDB簡介

banq發表於2024-04-16

DuckDB是一個記憶體分析型關聯式資料庫,主要用於資料分析。由於其列式儲存性質(單獨儲存每列的資料),它被視為分析資料庫。相比之下,傳統的關聯式資料庫採用基於行的儲存,逐行儲存資料。

DuckDB 的優點包括:

  • 快速查詢——DuckDB利用列式向量化查詢執行引擎來最佳化大批次的資料查詢。
  • SQL相容性——DuckDB支援標準SQL查詢,例如聚合和視窗函式,非常適合熟悉SQL的資料分析師。
  • 快速部署 - DuckDB 具有最小的外部依賴性,並且在我們的應用程式程序中執行,無需單獨的資料庫例項,從而使部署和整合變得簡單。
  • 免費 – DuckDB 是一個開源專案,可供所有人免費使用。其完整原始碼可在 GitHub 上訪問以供探索和貢獻。

DuckDB安裝
DuckDB 提供了各種安裝選項來適應我們的環境。我們將在這裡演示兩種常見的安裝方法。

1.命令列
對於Windows使用者,我們可以使用WinGet包管理器安裝DuckDB 。我們所需要做的就是使用管理員許可權開啟命令提示符並執行以下命令:
winget install DuckDB.cli

在 Mac OS 上,我們可以使用Homebrew安裝它:
brew install duckdb

完成DuckDB CLI的安裝後,brew會自行將二進位制路徑新增到現有環境變數中。我們可以開啟一個新的 shell 會話並透過執行以下命令來執行 DuckDB CLI:
duckdb

Java
DuckDB 可以與 Java 整合,無需安裝單獨的資料庫例項。首先,我們在pom.xml中包含以下DuckDB JDBC依賴項:

<dependency>
    <groupId>org.duckdb</groupId>
    <artifactId>duckdb_jdbc</artifactId>
    <version>0.10.0</version>
</dependency>

我們可以載入 DuckDB JDBC 驅動程式,然後透過以下JDBC URL建立 JDBC 連線:

Class.forName(<font>"org.duckdb.DuckDBDriver");
Connection conn = DriverManager.getConnection(
"jdbc:duckdb:");

當我們連線到 DuckDB 時,預設情況下它會自動建立一個記憶體資料庫例項。但是,一旦 DuckDB 程序完成,例項中保留的所有資料都會丟失。要將資料儲存到磁碟中,我們可以在連線 URL 中的冒號後面附加一個資料庫名稱:

Connection conn = DriverManager.getConnection(<font>"jdbc:duckdb:/test_duckdb");

在此示例中,DuckDB在根目錄中建立一個名為test_duckdb的資料庫檔案。由於這是一個 JDBC 庫,我們可以透過建立 SQL語句並執行它來獲取ResultSet來查詢資料。下面是一個獲取當前日期的簡單 JDBC 示例:

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(<font>"SELECT current_date");
Date currentDate = rs.next() ? rs.getDate(1) : null;

在本教程的後續部分中,我們可以在 Java 中使用相同的 JDBC 方法執行 SQL 語句。

資料匯入
讓我們繼續將一些資料匯入 DuckDB。它可以處理各種資料格式,從而簡化從外部資料來源的匯入。

1. CSV 檔案
CSV 是一種用於儲存表格資料的常見資料格式。假設我們有以下包含客戶資料的 CSV 檔案:

CustomerId,FirstName,LastName,Gender
101,John,Smith,Male
102,Sarah,Jones,Female
...

我們可以使用 SQL 函式read_csv將資料從 CSV 檔案匯入到 DuckDB 表customer中:

CREATE TABLE customer AS 
SELECT * FROM read_csv('customer.csv')

DuckDB 可以從 CSV 檔案的標題行找出架構。標題名稱被視為表列名稱,而後續行則被視為資料行。

2 JSON 檔案
另一種流行的儲存和共享資料的方式是 JSON。例如,我們採用以下product.json JSON 檔案:

[
  {
    <font>"productId": 1,
   
"productName":"EZ Curl Bar",
   
"category": "Sports Equipment"
  },
  {
   
"productId": 2,
   
"productName": "7' Barbell",
   
"category": "Sports Equipment"
  }
]

與CSV匯入類似,我們可以執行一條SQL語句將資料匯入到DuckDB表product中:

CREATE TABLE product AS 
SELECT * FROM read_json('product.json')

就像 CSV 一樣,DuckDB 根據 JSON 屬性名稱自動從 JSON 檔案中找出架構。

3.插入語句
我們可以使用插入語句向 DuckDB 表新增資料,因為它是一個 SQL 關聯式資料庫系統。下面的示例說明了建立一個定義客戶和產品之間關係的購買表 並填充幾行資料:

CREATE TABLE purchase(customerId BIGINT, productId BIGINT);
INSERT INTO purchase(customerId, productId) VALUES (101,1);
INSERT INTO purchase(customerId, productId) VALUES (102,1);
INSERT INTO purchase(customerId, productId) VALUES (102,2);


資料查詢
載入資料後,我們現在將探索查詢 DuckDB 並分析我們的資料。

1.加盟運營
除了將外部資料匯入到DuckDB之外,我們還可以直接使用外部資料。根據前面的示例,我們將利用上一節中的三個資料來源。現在,讓我們加入這些資料來源來收集有關客戶產品的資訊。

SELECT C.firstName, C.lastName, P.productName
FROM read_csv('customer.csv') AS C, read_json('product.json') AS P, purchase S 
WHERE S.customerId = C.customerId
AND S.productId = P.productId 

執行後,我們將看到以下查詢結果,顯示客戶名稱及其對應的產品購買情況:

名    姓    產品名稱
約翰    史密斯    EZ 彎杆
莎拉    瓊斯    7′槓鈴
莎拉    瓊斯    EZ 彎杆

2.聚合函式
DuckDB 提供了一組豐富的聚合函式來對行組執行計算。讓我們探討一下具有這些函式的示例:

SELECT P.productName, COUNT(*) AS purchaseCount
FROM customer C, product P, purchase S
WHERE S.customerId = C.customerId
AND S.productId = P.productId 
GROUP BY P.productName
ORDER BY COUNT(*) DESC

查詢統計每個商品的購買次數,並按購買次數降序排列


資料匯出
在資料分析任務中,我們經常需要將聚合資料匯出到其他應用程式以進行進一步分析。

讓我們逐步瞭解一下以各種格式從 DuckDB 匯出資料的過程。在我們的示例中,我們首先建立一個資料庫檢視,以便於稍後說明匯出:

CREATE VIEW purchase_view AS
SELECT P.productName, COUNT(*) AS purchaseCount
FROM customer C, product P, purchase S
WHERE S.customerId = C.customerId
AND S.productId = P.productId 
GROUP BY P.productName
ORDER BY COUNT(*) DESC;

1. CSV 檔案
在 DuckDB 中將資料匯出到 CSV 檔案非常簡單。我們可以執行以下簡單的 SQL 將資料庫檢視buy_view中的所有資料複製到位於根目錄中的 CSV 檔案:

COPY purchase_view TO '/output.csv'

2. JSON 檔案
要將資料匯出到 JSON 檔案,我們需要包含一個附加選項陣列來指定將資料寫入 JSON 陣列。這可確保我們匯出的 JSON 檔案具有適當的結構:

COPY (SELECT * FROM purchase_view WHERE purchaseCount > 1) TO '/output.json' (array true);

我們可以根據選擇查詢的條件複製部分結果,而不是匯出所有資料。