Skip to content
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

アプリ:mysqlの取り扱い, mysql ライブラリ #10

Open
cocoeyes02 opened this issue Jul 21, 2019 · 7 comments
Open

アプリ:mysqlの取り扱い, mysql ライブラリ #10

cocoeyes02 opened this issue Jul 21, 2019 · 7 comments

Comments

@cocoeyes02
Copy link
Collaborator

cocoeyes02 commented Jul 21, 2019

  • コネクションプールの設定とか
    • go の mysql ライブラリ
      • 例 gorm → github.com/go-sql-driver/mysql
    • N+1の取り扱い
      • コード例を示す
@cocoeyes02
Copy link
Collaborator Author

cocoeyes02 commented Aug 9, 2019

N+1 について

@cocoeyes02
Copy link
Collaborator Author

mapを使う方法

https://medium.com/eureka-engineering/golang-beginner-2d687bd8a831

Before:

// 例 いいねをしたお相手一覧を取得する
// ユーザーの使ったいいねのデータを取得
likes, _ := FindLikesByUserID(meID)
responses := make([]UserResponse, len(likes))
for i, like := range likes {
    r := UserResponse{}
    partnerID := like.PartnerID
    // partnerIDからお相手の情報を取得
    // select * from `user` where `id` = [partnerID]
    p, _ := FindUserByID(partnerID)
    r.ID = p.ID
    r.Name = p.Name
    // お相手の画像を取得
    // select * from `user_image` where `user_id` = [partnerID]
    image, _ := FindUserImageByUserID(partnerID)
    r.ImagePath = image.Path
    responses[i] = r
}

After:

// ユーザーの使ったいいねのデータを取得
likes, _ := FindLikesByUserID(meID)
partnerIDs := make([]int64, len(likes))
for i, like := range likes {
    partnerIDs[i] = like.PartnerID
}
// お相手の情報を取得
// select * from `user` where `id` in ([partnerIDs])
partners, _ := FindUsersByIDs(partnerIDs)
partnerMap := map[int64]User{}
for _, p := range partners {
    partnerMap[p.ID] = p
}
// お相手の画像を取得
// select * from `user_image` where `user_id` in ([partnerIDs])
images, _ := FindUserImagesByUserIDs(partnerIDs)
partnerImageMap := map[int64]UserImage{}
for _, image := range images {
    partnerImageMap[image.UserID] = image
}
responses := make([]UserResponse, len(partnerIDs))
for i, id := range partnerIDs {
    r := UserResponse{}
    if p, ok := partnerMap[id]; ok {
        r.ID = p.ID
        r.Name = p.Name
    }
    if image, ok := partnerImageMap[id]; ok {
        r.ImagePath = image.Path
    }
    responses[i] = r
}
処理の内容を簡単にまとめると
1. 取得したlikes からお相手のidのスライスを生成 — partnerIDs
2. お相手の情報、お相手の画像をそれぞれ partnerIDsでまとめて取得
3. 取得したスライスをお相手のIDをキーにしてmapに展開
4. レスポンス生成時にpartnerIDからそれぞれの構造体を取得
5. レスポンススライスにいれる

@cocoeyes02
Copy link
Collaborator Author

cocoeyes02 commented Aug 9, 2019

eagar load を利用する方法

(gorm などを使っているなら)eagar load を狙った preload

http://gorm.io/docs/preload.html

db.Preload("Orders").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4);

db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');

db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users WHERE state = 'active';
// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');

db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to

@cocoeyes02
Copy link
Collaborator Author

cocoeyes02 commented Aug 9, 2019

joins を利用する方法

(database/sql などを使っているなら)を使っていっぺんにデータ取得

@cocoeyes02
Copy link
Collaborator Author

cocoeyes02 commented Aug 9, 2019

# 直接解消編
go-sql-driver/mysql を使っているなら
→join で一度に取得

gorm などのORMマッパーを使っているなら
→ eagar load を狙った preload

上記が難しいなら
→ 個別にクエリを実行して、map を使って整形する

# 間接解消編
使っていない値を取得してくる処理は消す

@cocoeyes02
Copy link
Collaborator Author

go の mysql ライブラリの変更はやってみないとわからんなあ…
一旦導入方法だけ

https://qiita.com/taizo/items/54f5f49c6102f86194b8

@cocoeyes02
Copy link
Collaborator Author

database/sqlSetMaxOpenConns で設定できる

コネクションプールのチューニングについてはこちら
https://qiita.com/methane/items/ccd3fd856b02b06c9452

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant