duckdb: 一個超火的數據庫,背後公司只有 18 人?

簡介

DuckDB 是一個嵌入式、內存中、SQL OLAP 數據庫管理系統。它提供了一種高效的方式來查詢和分析數據, 可以被集成到各種應用程序或編程語言中。

最近非常的 🔥,一個月下載超過 200 萬次。實際上,這家位於荷蘭阿姆斯特丹的小型公司只有 18 人,下面這篇公衆號介紹了它的背景:震驚:開發一款世界矚目的數據庫僅需 18 人。這讓我想起了 clickhous。duckdb 的簡單易用、提供了便利的方法、功能強大讓它朝着成功邁進。

它的名字來自於創始人的寵物鴨子。

DuckDB 的主要特點包括:

  1. 嵌入式: DuckDB 可以作爲一個庫集成到應用程序中, 而不需要單獨的服務器進程。這使得它特別適合於嵌入式系統、物聯網設備和 Edge 計算場景。

  2. 內存中: DuckDB 將數據加載到內存中進行查詢, 這使得它在查詢速度和並行性能方面表現出色。對於中小型數據集, DuckDB 可以提供接近原生查詢速度。

  3. SQL 兼容性: DuckDB 支持標準的 SQL 語言, 包括大部分 SQL 語句和函數。它旨在提供高度的 SQL 兼容性, 使遷移和集成變得更加容易。

  4. 矢量化執行: DuckDB 採用了矢量化執行模型, 可以有效利用現代 CPU 的 SIMD 指令集, 從而提高查詢性能。

  5. 數據格式支持: 除了內置的行 Store 和列 Store,DuckDB 還支持直接查詢常見的文件格式, 如 CSV、Parquet、JSONL 等。

  6. 查詢優化器: DuckDB 內置了成本模型驅動的查詢優化器, 能夠生成高效的執行計劃。

  7. 可擴展性: DuckDB 支持通過插件擴展自定義函數和數據格式, 使其能夠更好地適應特定的應用場景。

  8. 多平臺支持: DuckDB 可以在多種操作系統和硬件架構上運行, 包括 Linux、Windows、macOS、ARM 等。

DuckDB 可以應用於許多場景, 如數據分析、ETL、機器學習特徵工程等。它可以作爲獨立的數據庫系統使用, 也可以集成到各種應用程序中, 爲高性能的數據處理和分析提供支持。

安裝

官方提供了多種環境的部署方式,不管是獨立程序還是作爲編程語言的庫。Mac/Linux/Windows 那是必須的,常見語言也有相應額度庫。

比如 Go 語言:

go get github.com/marcboeker/go-duckdb
package main

import (
"database/sql"
"fmt""github.com/marcboeker/go-duckdb"
)

func main() {
// 一個內存庫
db, _ := sql.Open("duckdb""")

// 創建表
db.Exec(`CREATE TABLE person (id INTEGER, name VARCHAR)`)
// 插入測試數據
db.Exec(`INSERT INTO person VALUES (42, 'John')`)

// 查詢數據
var (
id   int
name string
)
row := db.QueryRow(`SELECT id, name FROM person`)
_ = row.Scan(&id, &name)
fmt.Println("id:", id, "name:", name)
}

也可以部署獨立程序,比如在 Mac 上:

brew install duckdb

啓動duckdb:

duckdb

官方文檔 [1] 提供了容易閱讀,全面的資料, 我在這裏就不進行翻譯。官方的文檔還是很詳細的,而且文檔組織的也是超一流的,方便查找和閱讀。

擴展

duckdb 還提供了很多的擴展,比如從 Mysql、Postgres、SQLite 中讀取數據,又比如下面這個 inet 提供了 Ip 地址數據類型:

INSTALL inet;
LOAD inet;
SELECT '127.0.0.1'::INET AS ipv4, '2001:db8:3c4d::/48'::INET AS ipv6;
CREATE TABLE tbl (id INTEGER, ip INET);
INSERT INTO tbl VALUES
    (1, '192.168.0.0/16'),
    (2, '127.0.0.1'),
    (3, '8.8.8.8'),
    (4, 'fe80::/10'),
    (5, '2001:db8:3c4d:15::1a2f:1a2b');
SELECT * FROM tbl;

接下來,我們以一個 IP 地理信息庫爲例,看看怎麼從 IP 地址查詢國家信息和城市信息。

實戰:IP 地理信息庫

IP 地理信息庫文件

IP 地理位置數據庫 世界城鎮擴展版 2021-11-08 | eMule Fans 電騾愛好者 [2] 網站提供了免費的 IP 地址世界城鎮庫以及 IP 地址中國城鎮庫。我們以世界城鎮庫爲例。

wget -o ip-to-country_csv.city.zip  https://github.com/emulefanscom/ip2c/releases/download/2021-11-08/ip-to-country_csv.city.zip
unzip ip-to-country_csv.city.zip

解壓開的文件大小爲 231 MB, CSV 格式的文件:

# ls
total 557344
-rw-r--r--@ 1 smallnest  staff   231M 11 10  2021 ip-to-country.csv
-rw-r--r--@ 1 smallnest  staff    34M 12  7  2021 ip-to-country_csv.city.zip

從 CSV 文件中進行加載

我們下載的 IP 庫文件中的數據格式如下,第一列是起始IP, 第二列是結束IP, 第三列是國家代碼(2碼),第四列是國家名稱(3碼),第五列是城市名稱-省名稱-國家名稱, 沒有 header。

"16777216","16777471","AU","AUS","South Brisbane - Queensland - Australia"
"16777472","16778239","CN","CHN","Qingzhou - Fujian - China"
"16778240","16779263","AU","AUS","Narre Warren - Victoria - Australia"
"16779264","16781311","CN","CHN","Guangzhou Shi - Guangdong - China"
"16781312","16785407","JP","JPN","Shinjuku - Tokyo - Japan"
"16785408","16793599","CN","CHN","Guangzhou Shi - Guangdong - China"
"16793600","16793855","JP","JPN","Hiroshima - Hiroshima - Japan"
"16793856","16794111","JP","JPN","Hiroshima - Hiroshima - Japan"
"16794112","16794367","JP","JPN","Hiroshima - Hiroshima - Japan"
"16794368","16794623","JP","JPN","Hiroshima - Hiroshima - Japan"

使用 duckdb 的read_csv函數從 CSV 文件中加載數據到表中 (read_csv_auto可以自動解析 csv,猜測數據類型和 header, 不過函數已經棄用了,可以使用功能更強大的read_csv)。注意因爲數據文件沒有 header,所以 1 這裏需要指定列名,否則會自動生成列名,而且我們指定了列的數據類型。

create table ip2country AS SELECT * FROM read_csv('ip-to-country.csv',
    header = false,
    columns = {
        ip_start: 'INT64',
        ip_end: 'INT64',
        country_tld: 'VARCHAR',
        country_code: 'VARCHAR',
        country_name: 'VARCHAR'
    }
);

從文件中加載還是飛快的,幾乎在 1 秒之內就加載完了。不知道是真的加載到內存中了還是僞加載。

接下來我們就可以使用這個數據庫進行分析了,比如我們查詢 8.8.8.8 這個 IP:

select * from ip2country where (
    SELECT (
      CAST(SPLIT_PART(ipv4, '.', 1) AS INT64) * 16777216 +
      CAST(SPLIT_PART(ipv4, '.', 2) AS INT64) * 65536 +
      CAST(SPLIT_PART(ipv4, '.', 3) AS INT64) * 256 +
      CAST(SPLIT_PART(ipv4, '.', 4) AS INT64)
    ) AS int_ip
    FROM (
        SELECT '8.8.8.8' AS ipv4
    )
  )
  between ip_start and ip_end;

因爲 duckdb 沒有函數把 ip 轉換成整數的函數,前面提到的 inet 插件也不行,所以我們通過 sql 語句來轉換。查詢出來的這個 IP 顯示它位於美國加州山景城,也就是谷歌的所在地:

接下來查詢一個我廠的 dns 服務器的 ip 地址看看:

select * from ip2country where (
    SELECT (
      CAST(SPLIT_PART(ipv4, '.', 1) AS INT64) * 16777216 +
      CAST(SPLIT_PART(ipv4, '.', 2) AS INT64) * 65536 +
      CAST(SPLIT_PART(ipv4, '.', 3) AS INT64) * 256 +
      CAST(SPLIT_PART(ipv4, '.', 4) AS INT64)
    ) AS int_ip
    FROM (
        SELECT '180.76.76.76' AS ipv4
    )
  )
  between ip_start and ip_end;

可以看到顯示這個 Ip 地址位於北京市: 

參考資料

[1]

官方文檔: https://duckdb.org/docs/installation/index

[2]

Emulefans: https://www.emulefans.com/ip-to-country-city-20211108/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/aAgDibroCEk0UQAI2NtZxg