Skip to content

go: Use interpolateParams=true for MySQL #1353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 6, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 26 additions & 27 deletions frameworks/Go/go/src/hello/hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,50 +28,48 @@ type Fortune struct {
Message string `json:"message"`
}

// Databases
const (
// Database
connectionString = "benchmarkdbuser:benchmarkdbpass@tcp(localhost:3306)/hello_world"
// Go 1.4's sql.DB has scalability problem when using (explicitly reused) prepared statement.
// https://github.com/golang/go/issues/9484
//
// Using db.Query() instead of stmt.Query() avoid the issue.
// But it makes 3 round trips per query: prepare, execute and close.
// `interpolateParams=true` enables client side parameter interpolation.
// It reduces round trips without prepared statement.
//
// Before Go 1.5 is released, we can see real power of Go with this benchmark.
// After Go 1.5 is released, we can see prepared statement vs interpolation by comparing
// this and another lightweight Go framework.
connectionString = "benchmarkdbuser:benchmarkdbpass@tcp(localhost:3306)/hello_world?interpolateParams=true"
worldSelect = "SELECT id, randomNumber FROM World WHERE id = ?"
worldUpdate = "UPDATE World SET randomNumber = ? WHERE id = ?"
fortuneSelect = "SELECT id, message FROM Fortune;"
worldRowCount = 10000
maxConnectionCount = 256

helloWorldString = "Hello, World!"
)

const helloWorldString = "Hello, World!"

var (
// Templates
tmpl = template.Must(template.ParseFiles("templates/layout.html", "templates/fortune.html"))

// Database
worldStatement *sql.Stmt
fortuneStatement *sql.Stmt
updateStatement *sql.Stmt
db *sql.DB

helloWorldBytes = []byte(helloWorldString)
)

func main() {
runtime.GOMAXPROCS(runtime.NumCPU())

db, err := sql.Open("mysql", connectionString)
var err error
db, err = sql.Open("mysql", connectionString)
if err != nil {
log.Fatalf("Error opening database: %v", err)
}
db.SetMaxIdleConns(maxConnectionCount)
worldStatement, err = db.Prepare(worldSelect)
if err != nil {
log.Fatal(err)
}
fortuneStatement, err = db.Prepare(fortuneSelect)
if err != nil {
log.Fatal(err)
}
updateStatement, err = db.Prepare(worldUpdate)
if err != nil {
log.Fatal(err)
}

http.HandleFunc("/db", dbHandler)
http.HandleFunc("/queries", queriesHandler)
Expand All @@ -91,7 +89,7 @@ func jsonHandler(w http.ResponseWriter, r *http.Request) {
// Test 2: Single database query
func dbHandler(w http.ResponseWriter, r *http.Request) {
var world World
err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
err := db.QueryRow(worldSelect, rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
if err != nil {
log.Fatalf("Error scanning world row: %s", err.Error())
}
Expand All @@ -114,7 +112,7 @@ func queriesHandler(w http.ResponseWriter, r *http.Request) {

world := make([]World, n)
for i := 0; i < n; i++ {
err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber)
err := db.QueryRow(worldSelect, rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber)
if err != nil {
log.Fatalf("Error scanning world row: %s", err.Error())
}
Expand All @@ -126,7 +124,7 @@ func queriesHandler(w http.ResponseWriter, r *http.Request) {

// Test 4: Fortunes
func fortuneHandler(w http.ResponseWriter, r *http.Request) {
rows, err := fortuneStatement.Query()
rows, err := db.Query(fortuneSelect)
if err != nil {
log.Fatalf("Error preparing statement: %v", err)
}
Expand All @@ -139,6 +137,7 @@ func fortuneHandler(w http.ResponseWriter, r *http.Request) {
}
fortunes = append(fortunes, &fortune)
}
rows.Close()
fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})

sort.Sort(ByMessage{fortunes})
Expand All @@ -160,18 +159,18 @@ func updateHandler(w http.ResponseWriter, r *http.Request) {

if n <= 1 {
var world World
worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
db.QueryRow(worldSelect, rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
world.RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
updateStatement.Exec(world.RandomNumber, world.Id)
db.Exec(worldUpdate, world.RandomNumber, world.Id)
encoder.Encode(&world)
} else {
world := make([]World, n)
for i := 0; i < n; i++ {
if err := worldStatement.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber); err != nil {
if err := db.QueryRow(worldSelect, rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber); err != nil {
log.Fatalf("Error scanning world row: %s", err.Error())
}
world[i].RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
if _, err := updateStatement.Exec(world[i].RandomNumber, world[i].Id); err != nil {
if _, err := db.Exec(worldUpdate, world[i].RandomNumber, world[i].Id); err != nil {
log.Fatalf("Error updating world row: %s", err.Error())
}
}
Expand Down