Golang操作DuckDB實(shí)戰(zhàn)案例分享
DuckDB的主要優(yōu)點(diǎn)
- 內(nèi)存內(nèi)執(zhí)行:DuckDB主要在內(nèi)存中操作,但也支持內(nèi)存外執(zhí)行。這使得它能夠非??焖儆行У貓?zhí)行計(jì)算。
- 完整的SQL支持:DuckDB支持廣泛的SQL特性,這使得它對(duì)于各種類(lèi)型的數(shù)據(jù)操作非常靈活。
- 事務(wù)支持:DuckDB支持事務(wù),這是在許多應(yīng)用程序中維護(hù)數(shù)據(jù)完整性和一致性的關(guān)鍵特性。
- 向量化執(zhí)行:DuckDB使用向量化查詢執(zhí)行,從而提高CPU利用率和性能。
- 易于集成:DuckDB為多種編程語(yǔ)言提供api,包括Python、R、c++、Rust、Java和Go。這使得將DuckDB集成到現(xiàn)有工作流和系統(tǒng)中變得更加容易。
- 開(kāi)源:DuckDB是開(kāi)源的,這意味著它的源代碼可以免費(fèi)修改或增強(qiáng)。這允許社區(qū)驅(qū)動(dòng)的改進(jìn)和對(duì)特定用例的適應(yīng)性。
環(huán)境準(zhǔn)備
在開(kāi)始使用DuckDB和Go之前,需要安裝DuckDB Go驅(qū)動(dòng)程序。你可以使用Go的包管理器下載。在終端上運(yùn)行以下命令:
github.com/marcboeker/go-duckdb
- 連接數(shù)據(jù)庫(kù)
package main import ( "database/sql" "log" _ "github.com/marcboeker/go-duckdb" ) func main() { // Empty datasource means, that DB will be solely in-memory, otherwise you could specify a filename here db, err := sql.Open("duckdb", "") if err != nil { log.Fatal("Failed to connect to database:", err) } defer db.Close() }
安裝了驅(qū)動(dòng)程序后,現(xiàn)在可以從Go應(yīng)用程序建立到DuckDB的連接。sql.Open() 函數(shù)用于連接到DuckDB,空數(shù)據(jù)源名稱(chēng)表示我們正在使用內(nèi)存中的數(shù)據(jù)庫(kù),你也可以指定數(shù)據(jù)庫(kù)文件名稱(chēng),實(shí)現(xiàn)數(shù)據(jù)持久化,相對(duì)于當(dāng)前項(xiàng)目所在目錄。
初始化表和數(shù)據(jù)
現(xiàn)在連接已經(jīng)建立,你可以執(zhí)行各種數(shù)據(jù)庫(kù)操作了。我們首先創(chuàng)建表,然后插入初始化數(shù)據(jù)進(jìn)行測(cè)試:
package main import ( "database/sql" "fmt" "log" "time" _ "github.com/marcboeker/go-duckdb" ) var db *sql.DB var err error func main() { // Empty datasource means, that DB will be solely in-memory, otherwise you could specify a filename here db, err = sql.Open("duckdb", "data.db") if err != nil { log.Fatal("Failed to connect to database:", err) } defer db.Close() init_data() } func init_data() { // Create table _, err := db.Exec(` CREATE TABLE employee ( id INTEGER, name VARCHAR(20), start_dt TIMESTAMP, is_remote BOOLEAN )`) if err != nil { log.Fatal(err) } // Insert some data in table _, err = db.Exec(` INSERT INTO employee (id, name, start_dt, is_remote) VALUES (1, 'John Doe', '2022-01-01 09:00:00', true), (2, 'Jane Smith', '2023-03-15 10:00:00', false)`) if err != nil { log.Fatal(err) } }
在處理較大的數(shù)據(jù)集時(shí),考慮使用事務(wù)和預(yù)處理語(yǔ)句以提高效率和安全性。記住,總是處理錯(cuò)誤并在完成后關(guān)閉連接。
查詢單行或多行
要獲取數(shù)據(jù),可以使用QueryRow() 函數(shù)來(lái)選擇單行:
func query_one() { // Variables to store query result var id int var name string var startDt time.Time var isRemote bool // Query single row if err := db.QueryRow("SELECT id, name, start_dt, is_remote FROM employee WHERE id = ?", 1).Scan(&id, &name, &startDt, &isRemote); err != nil { if err == sql.ErrNoRows { log.Println("No rows found.") } else { log.Fatalf("unable to execute query: %v", err) } } else { fmt.Println("Select 1 row result:\nID:", id, "Name:", name, "Start Datetime:", startDt, "Is Remote:", isRemote) } }
不要忘記處理任何錯(cuò)誤并正確關(guān)閉連接和結(jié)果集,如上所示。
要選擇多行,可以使用Query() 函數(shù):
func query_all() { // Variables to store query result var id int var name string var startDt time.Time var isRemote bool // Query multiple rows rows, err := db.Query("SELECT id, name, start_dt, is_remote FROM employee") if err != nil { log.Fatal(err) } defer rows.Close() // Print the results fmt.Println("Results:") for rows.Next() { err = rows.Scan(&id, &name, &startDt, &isRemote) if err != nil { log.Fatal(err) } fmt.Println("ID:", id, "Name:", name, "Start Datetime:", startDt, "Is Remote:", isRemote) } err = rows.Err() if err != nil { log.Fatal(err) } }
我們用SQL命令調(diào)用Query()函數(shù),從employee表中選擇所有記錄。
- 然后使用rows.Next()進(jìn)入循環(huán),該循環(huán)遍歷查詢返回的每一行。
- 在循環(huán)中,我們使用Scan()函數(shù)將當(dāng)前行的列復(fù)制到id、name、startDt和isRemote變量中。
- 然后使用fmt.Println()函數(shù)打印這些變量。
- 循環(huán)結(jié)束后,使用rows.Err()檢查迭代過(guò)程中的錯(cuò)誤。如果有錯(cuò)誤,我們使用log.Fatal(err)打印它。
錯(cuò)誤處理和事務(wù)
在現(xiàn)實(shí)世界中,Go代碼必須準(zhǔn)備好處理錯(cuò)誤和處理事務(wù)。SQL包提供了所有必要的工具:
func trans_insert() { // Error handling and transactions tx, err := db.Begin() if err != nil { log.Fatal(err) } defer tx.Rollback() _, err = tx.Exec(` INSERT INTO employee (id, name, start_dt, is_remote) VALUES (3000000000, 'id int64 instead of int32', '2022-06-17 11:00:00', true)`) if err != nil { log.Printf("ERROR: %s\n", err.Error()) // Do not fail, just print the error in output } err = tx.Commit() if err != nil { log.Fatal(err) } }
此代碼開(kāi)始事務(wù),嘗試執(zhí)行插入語(yǔ)句,然后提交事務(wù)。如果在執(zhí)行期間發(fā)生錯(cuò)誤,它將回滾在該事務(wù)中所做的任何更改。
完整代碼
package main import ( "database/sql" "fmt" "log" "time" _ "github.com/marcboeker/go-duckdb" ) var db *sql.DB var err error func main() { // Empty datasource means, that DB will be solely in-memory, otherwise you could specify a filename here db, err = sql.Open("duckdb", "data.db") if err != nil { log.Fatal("Failed to connect to database:", err) } defer db.Close() // init_data() query_one() // trans_insert() query_all() } func init_data() { // Create table _, err = db.Exec(` CREATE TABLE employee ( id INTEGER, name VARCHAR(20), start_dt TIMESTAMP, is_remote BOOLEAN )`) if err != nil { log.Fatal(err) } // Insert some data in table _, err = db.Exec(` INSERT INTO employee (id, name, start_dt, is_remote) VALUES (1, 'John Doe', '2022-01-01 09:00:00', true), (2, 'Jane Smith', '2023-03-15 10:00:00', false)`) if err != nil { log.Fatal(err) } } func trans_insert() { // Error handling and transactions tx, err := db.Begin() if err != nil { log.Fatal(err) } defer tx.Rollback() _, err = tx.Exec(` INSERT INTO employee (id, name, start_dt, is_remote) VALUES (3000000000, 'id int64 instead of int32', '2022-06-17 11:00:00', true)`) if err != nil { log.Printf("ERROR: %s\n", err.Error()) // Do not fail, just print the error in output } err = tx.Commit() if err != nil { log.Fatal(err) } } func query_one() { // Variables to store query result var id int var name string var startDt time.Time var isRemote bool // Query single row if err := db.QueryRow("SELECT id, name, start_dt, is_remote FROM employee WHERE id = ?", 1).Scan(&id, &name, &startDt, &isRemote); err != nil { if err == sql.ErrNoRows { log.Println("No rows found.") } else { log.Fatalf("unable to execute query: %v", err) } } else { fmt.Println("Select 1 row result:\nID:", id, "Name:", name, "Start Datetime:", startDt, "Is Remote:", isRemote) } } func query_all() { // Variables to store query result var id int var name string var startDt time.Time var isRemote bool // Query multiple rows rows, err := db.Query("SELECT id, name, start_dt, is_remote FROM employee") if err != nil { log.Fatal(err) } defer rows.Close() // Print the results fmt.Println("Results:") for rows.Next() { err = rows.Scan(&id, &name, &startDt, &isRemote) if err != nil { log.Fatal(err) } fmt.Println("ID:", id, "Name:", name, "Start Datetime:", startDt, "Is Remote:", isRemote) } err = rows.Err() if err != nil { log.Fatal(err) } }
最后總結(jié)
DuckDB對(duì)Go的支持允許開(kāi)發(fā)人員直接從他們的Go應(yīng)用程序中執(zhí)行強(qiáng)大的數(shù)據(jù)分析操作。強(qiáng)大的數(shù)據(jù)管理系統(tǒng)和通用高效的編程語(yǔ)言之間的這種集成為更先進(jìn)的數(shù)據(jù)處理應(yīng)用打開(kāi)了大門(mén)。有了本文提供的基礎(chǔ)知識(shí),你就可以開(kāi)始探索這些可能性了。
以上就是Golang操作DuckDB實(shí)戰(zhàn)案例分享的詳細(xì)內(nèi)容,更多關(guān)于Golang操作DuckDB的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang開(kāi)發(fā)庫(kù)的集合及作用說(shuō)明
這篇文章主要為大家介紹了Golang開(kāi)發(fā)golang庫(kù)的集合及簡(jiǎn)單的作用說(shuō)明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11golang基于websocket通信tcp keepalive研究記錄
這篇文章主要為大家介紹了golang基于websocket通信tcp keepalive研究記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06基于Go語(yǔ)言實(shí)現(xiàn)高性能文件上傳下載系統(tǒng)
在Web應(yīng)用開(kāi)發(fā)中,文件上傳下載是一個(gè)非常常見(jiàn)的需求,本文將介紹如何使用Go語(yǔ)言實(shí)現(xiàn)一個(gè)安全、高效的本地文件存儲(chǔ)系統(tǒng),感興趣的小伙伴可以了解下2025-03-03Go基礎(chǔ)教程系列之WaitGroup用法實(shí)例詳解
這篇文章主要介紹了Go基礎(chǔ)教程系列之WaitGroup用法實(shí)例詳解,需要的朋友可以參考下2022-04-04Golang中interface{}轉(zhuǎn)為數(shù)組的操作
這篇文章主要介紹了Golang中interface{}轉(zhuǎn)為數(shù)組的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04