Closed4
プリペアードステートメントについてさっくり整理

Reference

概要
-
SQL文を「構文解析(パース)」した状態で一度サーバーに送信し、その後は値のバインドだけで繰り返し実行できる仕組み。
-
ざっくりな流れ:
- DBを利用するクライアントから、まず変数を埋め込み可能な形式のSQLを発行。
- DB側でそのSQLを受け取り、解析した上でキャッシュに乗せる。
- クライアントからは変数のみを送ってSQLを実行する。
-
利点:
- 同じSQLを何度も実行する場合、実行計画にキャッシュさせておくことでDB効率よくなる。
- クエリをパラメータを分離させることで、SQLインジェクション対策にもなる。
-
使用例 (goの場合):
stmt = db.prepare("INSERT INTO users (name, age) VALUES (?, ?)") stmt.execute("Alice", 25)

補足事項
- webアプリケーションでは発行するクエリの種類が多く、作成したプリペアードステートメントのキャッシュが効率よく利用されないケースが多い。
- 結果として、SQLを発行する度にプリペアードステートメントを準備する、
PREPARE
クエリと、作成したステートメントを開放するCLOSE
のクエリが必要になり、通信回数が増えることで効率が低下してしまいがち。 - Goの場合は、go-sql-driver/mysql ではプリペアードステートメントはデフォルトで有効になってるため、無効化したい場合は明示的に指定する必要がある。

func NewDatabaseConnection() (*sql.DB, error) {
c := mysqldriver.Config{
User: cfg.Get().DB.User,
Passwd: cfg.Get().DB.Pass,
Addr: fmt.Sprintf("%s:%s", cfg.Get().DB.Host, cfg.Get().DB.Port),
DBName: cfg.Get().DB.Name,
ParseTime: true,
Net: "tcp",
AllowNativePasswords: true,
Params: map[string]string{
"interpolateParams": "true", // ここで設定
},
}
db, err := sql.Open("mysql", c.FormatDSN())
if err != nil {
return nil, err
}
return db, nil
}
このスクラップは4ヶ月前にクローズされました