Go データベース/SQL パッケージを使用して実行されたクエリは、データベースに対して直接実行された同等のクエリよりも大幅に遅い。この不一致に対処するには、基礎となるメカニズムを詳しく調べることが重要です。
sql.DB オブジェクトは、単一の接続ではなく、接続のプールを表します。 sql.Open が呼び出されると、プールは初期化されますが、接続は確立されない場合があります。クエリがリクエストされた場合にのみ、新しい接続が作成されます。
提供されたコード スニペットでは、最初のクエリは新しい接続の作成をトリガーするため、パフォーマンス ヒットが発生します。データベース接続。 2 番目のクエリでも、接続の再利用がないため、パフォーマンスのギャップが見られます。各クエリは、プールからの既存のアイドル接続を利用するのではなく、新しい接続を確立します。
この問題を解決するには、接続をプールに解放することが重要です。各クエリの後。これは、クエリ結果を表す 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())) } }
Byこれらの最適化を実装すると、クエリのパフォーマンスのギャップが大幅に削減され、直接クエリと同等の実行時間が得られます。
以上がGo のデータベース/SQL がデータベースの直接クエリよりも遅いのはなぜですか? それを修正するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。