使用Go 資料庫/sql 套件執行的查詢比直接針對資料庫執行的等效查詢慢得多。為了解決這種差異,必須深入研究底層機制。
sql.DB 物件代表一個連線池,而不是單一連線。當呼叫 sql.Open 時,它會初始化池,但可能不會建立任何連線。僅當請求查詢時,才會建立新連線。
在提供的程式碼片段中,第一個查詢遇到效能影響,因為它觸發了新連接的建立資料庫連線。由於缺乏連接重用,第二個查詢也表現出效能差距。每個查詢都會建立一個新連接,而不是利用池中現有的空閒連接。
要解決此問題,將連線釋放回池至關重要每次查詢後。這可以透過保留 db.Query 的第一個傳回值(代表查詢結果)並對其呼叫 .Close() 來實現。
從池中的可用連接,在初始化後對 sql.DB 物件呼叫 Ping。這將強制建立初始連線。
當查詢包含參數時使用準備好的語句。 Postgres 協定支援參數,而不是直接將值插入查詢字串中。這種單獨的參數化可以更有效地處理查詢。
以下程式碼片段說明如何正確管理連接和重複使用準備好的語句:
package main import ( "database/sql" "fmt" _ "github.com/lib/pq" "time" ) func main() { // Initialize database connection with initial idle connection db, err := sql.Open("postgres", "postgres:///?sslmode=disable") if err != nil { panic(err) } if err := db.Ping(); err != nil { panic(err) } for i := 0; i < 5; i++ { // Prepare query query := "select 1 where true" stmt, err := db.Prepare(query) if err != nil { panic(err) } // Execute and time query firstQueryStart := time.Now() rows, err := stmt.Query() firstQueryEnd := time.Now() if err != nil { panic(err) } // Release connection back to pool rows.Close() fmt.Println(fmt.Sprintf("query #%d took %s", i, firstQueryEnd.Sub(firstQueryStart).String())) } }
透過實作這些最佳化,可以顯著縮小查詢效能差距,提供與直接查詢相當的執行時間。
以上是為什麼Go中的database/sql比直接資料庫查詢慢,我該如何解決?的詳細內容。更多資訊請關注PHP中文網其他相關文章!