Open sunakan opened 14 hours ago
+-------+--------+--------------------------------------+--------+--------+--------+---------+
| COUNT | METHOD | URI | MIN | AVG | MAX | SUM |
+-------+--------+--------------------------------------+--------+--------+--------+---------+
| 578 | GET | /api/livestream/\d+/livecomment | 0.004 | 0.252 | 1.136 | 145.417 |
| 609 | GET | /api/livestream/\d+/reaction | 0.004 | 0.230 | 1.332 | 139.882 |
| 34 | POST | /api/livestream/\d+/moderate | 0.188 | 3.536 | 6.985 | 120.239 |
| 627 | POST | /api/livestream/\d+/livecomment | 0.004 | 0.153 | 0.632 | 95.801 |
| 5468 | GET | /api/user/\w+/icon | 0.016 | 0.013 | 0.612 | 71.424 |
| 11 | GET | /api/user/\w+/statistics | 0.452 | 5.127 | 6.713 | 56.393 |
| 80 | GET | /api/livestream/search | 0.040 | 0.662 | 1.500 | 52.972 |
| 537 | POST | /api/livestream/\d+/reaction | 0.004 | 0.095 | 1.428 | 50.985 |
| 310 | POST | /api/register | 0.004 | 0.149 | 0.884 | 46.096 |
| 125 | POST | /api/livestream/reservation | 0.004 | 0.367 | 0.884 | 45.821 |
| 309 | POST | /api/icon | 0.012 | 0.122 | 0.621 | 37.757 |
| 315 | POST | /api/login | 0.004 | 0.066 | 0.848 | 20.800 |
| 1 | POST | /api/initialize | 13.704 | 13.704 | 13.704 | 13.704 |
| 108 | GET | /api/tag | 0.004 | 0.080 | 0.664 | 8.680 |
| 212 | GET | /api/livestream | 0.004 | 0.028 | 0.592 | 5.924 |
| 70 | GET | /api/livestream/\d+/report | 0.004 | 0.078 | 0.544 | 5.472 |
| 2 | GET | /api/livestream/\d+/statistics | 2.720 | 2.736 | 2.752 | 5.472 |
| 50 | GET | /api/livestream/\d+/ngwords | 0.008 | 0.099 | 0.388 | 4.932 |
| 57 | POST | /api/livestream/\d+/enter | 0.004 | 0.079 | 0.368 | 4.508 |
| 48 | DELETE | /api/livestream/\d+/exit | 0.008 | 0.064 | 0.280 | 3.048 |
| 10 | GET | /api/user/\w+/theme | 0.004 | 0.049 | 0.200 | 0.488 |
| 2 | GET | /api/user/endoyui0/livestream | 0.092 | 0.176 | 0.260 | 0.352 |
| 1 | GET | /api/user/kazuyasato0/livestream | 0.296 | 0.296 | 0.296 | 0.296 |
| 2 | GET | /api/user/kazuya580/livestream | 0.112 | 0.142 | 0.172 | 0.284 |
| 1 | GET | /api/user/iyamamoto1/livestream | 0.056 | 0.056 | 0.056 | 0.056 |
| 1 | GET | /api/user/kanasasaki0/livestream | 0.048 | 0.048 | 0.048 | 0.048 |
| 1 | GET | /api/user/nakamuraryohei0/livestream | 0.040 | 0.040 | 0.040 | 0.040 |
| 1 | GET | /api/user/csasaki0/livestream | 0.036 | 0.036 | 0.036 | 0.036 |
| 1 | GET | /api/payment | 0.004 | 0.004 | 0.004 | 0.004 |
| 3 | GET | /api/user/me | 0.000 | 0.001 | 0.004 | 0.004 |
| 1 | GET | /api/user/test | 0.004 | 0.004 | 0.004 | 0.004 |
| 1 | GET | /api/livestream/\d+ | 0.004 | 0.004 | 0.004 | 0.004 |
+-------+--------+--------------------------------------+--------+--------+--------+---------+
+-------+--------+--------------------------------------+--------+--------+--------+---------+
| COUNT | METHOD | URI | MIN | AVG | MAX | SUM |
+-------+--------+--------------------------------------+--------+--------+--------+---------+
| 578 | GET | /api/livestream/\d+/livecomment | 0.004 | 0.252 | 1.136 | 145.417 |
| 609 | GET | /api/livestream/\d+/reaction | 0.004 | 0.230 | 1.332 | 139.882 |
| 34 | POST | /api/livestream/\d+/moderate | 0.188 | 3.536 | 6.985 | 120.239 |
| 627 | POST | /api/livestream/\d+/livecomment | 0.004 | 0.153 | 0.632 | 95.801 |
| 5468 | GET | /api/user/\w+/icon | 0.016 | 0.013 | 0.612 | 71.424 |
GETが上位にきているので、カイゼンの余地ありそう
pt-query-digest --limit 10 tmp/analysis/latest/mysql-slow.log.*
# 19.1s user time, 120ms system time, 52.23M rss, 392.13G vsz
# Current date: Mon Sep 23 00:27:16 2024
# Hostname: CWPC20001.local
# Files: tmp/analysis/latest/mysql-slow.log.isu-1, tmp/analysis/latest/mysql-slow.log.isu-2, tmp/analysis/latest/mysql-slow.log.isu-3
# Overall: 451.35k total, 94 unique, 4.47k QPS, 2.97x concurrency ________
# Time range: 2024-09-22T15:17:57 to 2024-09-22T15:19:38
# Attribute total min max avg 95% stddev median
# ============ ======= ======= ======= ======= ======= ======= =======
# Exec time 300s 1us 408ms 664us 2ms 3ms 152us
# Lock time 1s 0 17ms 2us 1us 75us 1us
# Rows sent 398.20k 0 7.32k 0.90 0.99 20.67 0.99
# Rows examine 20.95M 0 14.03k 48.66 6.98 717.28 0.99
# Query size 66.08M 5 1.94M 153.51 329.68 3.57k 42.48
# Profile
# Rank Query ID Response time Calls R/Call V/M
# ==== =================================== ============= ====== ====== ===
# 1 0x4ADE2DC90689F1C4891749AF54FB8D14 39.4575 13.2% 51187 0.0008 0.00 DELETE SELECT livecomments
# 2 0xFBC5564AE716EAE82F20BFB45F6C37E7 27.9182 9.3% 69338 0.0004 0.00 SELECT tags
# 3 0x84B457C910C4A79FC9EBECB8B1065C66 24.9622 8.3% 28556 0.0009 0.00 SELECT icons
# 4 0x64CC8A4E8E4B390203375597CE4D611F 21.9347 7.3% 573 0.0383 0.01 SELECT ng_words
# 5 0xFFFCA4D67EA0A788813031B8BBC3B329 19.9211 6.6% 4374 0.0046 0.01 COMMIT
# 6 0x59F1B6DD8D9FEC059E55B3BFD624E8C3 18.8240 6.3% 1090 0.0173 0.01 SELECT reservation_slots
# 7 0x22279D81D51006139E0C76405B54C261 14.8477 5.0% 28114 0.0005 0.00 SELECT domains domainmetadata
# 8 0x38BC86A45F31C6B1EE324671506C898A 13.9448 4.7% 27386 0.0005 0.00 SELECT themes
# 9 0x42EF7D7D98FBCC9723BF896EBFC51D24 12.4449 4.2% 22510 0.0006 0.00 SELECT records
# 10 0xEA1E6309EEEFF9A6831AD2FB940FC23C 11.5867 3.9% 27068 0.0004 0.00 SELECT users
# MISC 0xMISC 93.9169 31.3% 191155 0.0005 0.0 <84 ITEMS>
# Query 1: 853.12 QPS, 0.66x concurrency, ID 0x4ADE2DC90689F1C4891749AF54FB8D14 at byte 105821212
# Scores: V/M = 0.00
# Time range: 2024-09-22T15:18:38 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 11 51187
# Exec time 13 39s 98us 30ms 770us 3ms 1ms 236us
# Lock time 14 178ms 0 8ms 3us 1us 78us 1us
# Rows sent 0 0 0 0 0 0 0 0
# Rows examine 0 99.99k 2 4 2.00 1.96 0.03 1.96
# Query size 24 16.22M 263 535 332.36 381.65 27.04 313.99
# String:
# Databases isupipe
# Hosts localhost
# Users isucon
# Query_time distribution
# 1us
# 10us #
# 100us ################################################################
# 1ms ##################
# 10ms #
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isupipe` LIKE 'livecomments'\G
# SHOW CREATE TABLE `isupipe`.`livecomments`\G
DELETE FROM livecomments
WHERE
id = 1005 AND
livestream_id = 7534 AND
(SELECT COUNT(*)
FROM
(SELECT 'あの敵、どうやって避けてるんですか?' AS text) AS texts
INNER JOIN
(SELECT CONCAT('%', '神経工学', '%') AS pattern) AS patterns
ON texts.text LIKE patterns.pattern) >= 1\G
# Converted for EXPLAIN
# EXPLAIN /*!50100 PARTITIONS*/
select * from livecomments
WHERE
id = 1005 AND
livestream_id = 7534 AND
(SELECT COUNT(*)
FROM
(SELECT 'あの敵、どうやって避けてるんですか?' AS text) AS texts
INNER JOIN
(SELECT CONCAT('%', '神経工学', '%') AS pattern) AS patterns
ON texts.text LIKE patterns.pattern) >= 1\G
# Query 2: 1.05k QPS, 0.42x concurrency, ID 0xFBC5564AE716EAE82F20BFB45F6C37E7 at byte 40555125
# Scores: V/M = 0.00
# Time range: 2024-09-22T15:18:32 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 15 69338
# Exec time 9 28s 43us 36ms 402us 2ms 820us 125us
# Lock time 21 266ms 0 7ms 3us 1us 72us 1us
# Rows sent 17 67.71k 1 1 1 1 0 1
# Rows examine 0 67.71k 1 1 1 1 0 1
# Query size 3 2.11M 31 33 31.95 31.70 0.47 31.70
# String:
# Databases isupipe
# Hosts localhost
# Users isucon
# Query_time distribution
# 1us
# 10us ##########################################################
# 100us ################################################################
# 1ms #############
# 10ms #
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isupipe` LIKE 'tags'\G
# SHOW CREATE TABLE `isupipe`.`tags`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT * FROM tags WHERE id = 62\G
# Query 3: 391.18 QPS, 0.34x concurrency, ID 0x84B457C910C4A79FC9EBECB8B1065C66 at byte 148783078
# Scores: V/M = 0.00
# Time range: 2024-09-22T15:18:25 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 6 28556
# Exec time 8 25s 68us 34ms 874us 3ms 1ms 332us
# Lock time 6 75ms 0 3ms 2us 1us 37us 1us
# Rows sent 5 23.86k 0 1 0.86 0.99 0.35 0.99
# Rows examine 0 23.86k 0 1 0.86 0.99 0.35 0.99
# Query size 1 1.19M 41 44 43.86 42.48 0.23 42.48
# String:
# Databases isupipe
# Hosts localhost
# Users isucon
# Query_time distribution
# 1us
# 10us ####
# 100us ################################################################
# 1ms #######################
# 10ms #
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isupipe` LIKE 'icons'\G
# SHOW CREATE TABLE `isupipe`.`icons`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT image FROM icons WHERE user_id = 1016\G
# Query 4: 8.19 QPS, 0.31x concurrency, ID 0x64CC8A4E8E4B390203375597CE4D611F at byte 26698340
# Scores: V/M = 0.01
# Time range: 2024-09-22T15:18:28 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 0 573
# Exec time 7 22s 4ms 122ms 38ms 75ms 20ms 34ms
# Lock time 0 3ms 0 2ms 4us 1us 84us 1us
# Rows sent 0 229 0 2 0.40 0.99 0.57 0
# Rows examine 37 7.84M 14.00k 14.03k 14.02k 13.78k 0 13.78k
# Query size 0 55.39k 97 99 98.99 97.36 0.27 97.36
# String:
# Databases isupipe
# Hosts localhost
# Users isucon
# Query_time distribution
# 1us
# 10us
# 100us
# 1ms ###
# 10ms ################################################################
# 100ms #
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isupipe` LIKE 'ng_words'\G
# SHOW CREATE TABLE `isupipe`.`ng_words`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT id, user_id, livestream_id, word FROM ng_words WHERE user_id = 1014 AND livestream_id = 7524\G
# Query 5: 59.92 QPS, 0.27x concurrency, ID 0xFFFCA4D67EA0A788813031B8BBC3B329 at byte 145646452
# Scores: V/M = 0.01
# Time range: 2024-09-22T15:18:25 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 0 4374
# Exec time 6 20s 23us 89ms 5ms 14ms 6ms 3ms
# Lock time 0 0 0 0 0 0 0 0
# Rows sent 0 0 0 0 0 0 0 0
# Rows examine 0 0 0 0 0 0 0 0
# Query size 0 25.63k 6 6 6 6 0 6
# String:
# Databases isupipe (4065/92%), isudns (309/7%)
# Hosts localhost
# Users isucon (4065/92%), isudns (309/7%)
# Query_time distribution
# 1us
# 10us #####################################
# 100us ##############
# 1ms ################################################################
# 10ms #################
# 100ms
# 1s
# 10s+
commit\G
# Query 6: 14.93 QPS, 0.26x concurrency, ID 0x59F1B6DD8D9FEC059E55B3BFD624E8C3 at byte 56825988
# Scores: V/M = 0.01
# Time range: 2024-09-22T15:18:25 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 0 1090
# Exec time 6 19s 2ms 80ms 17ms 42ms 13ms 13ms
# Lock time 0 8ms 0 7ms 7us 1us 197us 1us
# Rows sent 0 1.06k 1 1 1 1 0 1
# Rows examine 43 9.11M 8.55k 8.55k 8.55k 8.55k 0 8.55k
# Query size 0 91.54k 86 86 86 86 0 86
# String:
# Databases isupipe
# Hosts localhost
# Users isucon
# Query_time distribution
# 1us
# 10us
# 100us
# 1ms ###################################
# 10ms ################################################################
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isupipe` LIKE 'reservation_slots'\G
# SHOW CREATE TABLE `isupipe`.`reservation_slots`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT slot FROM reservation_slots WHERE start_at = 1701126000 AND end_at = 1701129600\G
# Query 7: 323.15 QPS, 0.17x concurrency, ID 0x22279D81D51006139E0C76405B54C261 at byte 120682509
# Scores: V/M = 0.00
# Time range: 2024-09-22T15:18:11 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 6 28114
# Exec time 4 15s 83us 33ms 528us 2ms 902us 194us
# Lock time 8 103ms 0 13ms 3us 1us 112us 1us
# Rows sent 0 0 0 0 0 0 0 0
# Rows examine 0 0 0 0 0 0 0 0
# Query size 4 3.03M 113 113 113 113 0 113
# String:
# Databases isudns
# Hosts localhost
# Users isudns
# Query_time distribution
# 1us
# 10us #
# 100us ################################################################
# 1ms ##########
# 10ms #
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isudns` LIKE 'domains'\G
# SHOW CREATE TABLE `isudns`.`domains`\G
# SHOW TABLE STATUS FROM `isudns` LIKE 'domainmetadata'\G
# SHOW CREATE TABLE `isudns`.`domainmetadata`\G
# EXPLAIN /*!50100 PARTITIONS*/
select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name='t.isucon.pw'\G
# Query 8: 375.15 QPS, 0.19x concurrency, ID 0x38BC86A45F31C6B1EE324671506C898A at byte 117744678
# Scores: V/M = 0.00
# Time range: 2024-09-22T15:18:25 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 6 27386
# Exec time 4 14s 74us 26ms 509us 2ms 919us 167us
# Lock time 6 77ms 0 5ms 2us 1us 51us 1us
# Rows sent 6 26.74k 1 1 1 1 0 1
# Rows examine 0 26.74k 1 1 1 1 0 1
# Query size 1 1.07M 38 41 40.90 40.45 0.56 40.45
# String:
# Databases isupipe
# Hosts localhost
# Users isucon
# Query_time distribution
# 1us
# 10us ####
# 100us ################################################################
# 1ms ##########
# 10ms #
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isupipe` LIKE 'themes'\G
# SHOW CREATE TABLE `isupipe`.`themes`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT * FROM themes WHERE user_id = 1054\G
# Query 9: 258.74 QPS, 0.14x concurrency, ID 0x42EF7D7D98FBCC9723BF896EBFC51D24 at byte 31809272
# Scores: V/M = 0.00
# Time range: 2024-09-22T15:18:11 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 4 22510
# Exec time 4 12s 90us 26ms 552us 2ms 932us 204us
# Lock time 4 60ms 0 7ms 2us 1us 54us 1us
# Rows sent 0 2.19k 0 1 0.10 0.99 0.30 0
# Rows examine 0 2.19k 0 1 0.10 0.99 0.30 0
# Query size 4 3.04M 128 214 141.43 151.03 11.68 136.99
# String:
# Databases isudns
# Hosts localhost
# Users isudns
# Query_time distribution
# 1us
# 10us #
# 100us ################################################################
# 1ms ##########
# 10ms #
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isudns` LIKE 'records'\G
# SHOW CREATE TABLE `isudns`.`records`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and name='pipe.t.isucon.pw' and domain_id=1\G
# Query 10: 370.79 QPS, 0.16x concurrency, ID 0xEA1E6309EEEFF9A6831AD2FB940FC23C at byte 69834330
# Scores: V/M = 0.00
# Time range: 2024-09-22T15:18:25 to 2024-09-22T15:19:38
# Attribute pct total min max avg 95% stddev median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count 5 27068
# Exec time 3 12s 51us 20ms 428us 2ms 869us 131us
# Lock time 7 88ms 0 6ms 3us 1us 64us 1us
# Rows sent 6 26.43k 1 1 1 1 0 1
# Rows examine 0 26.43k 1 1 1 1 0 1
# Query size 1 922.55k 32 35 34.90 34.95 0.54 34.95
# String:
# Databases isupipe
# Hosts localhost
# Users isucon
# Query_time distribution
# 1us
# 10us #################################################
# 100us ################################################################
# 1ms ############
# 10ms #
# 100ms
# 1s
# 10s+
# Tables
# SHOW TABLE STATUS FROM `isupipe` LIKE 'users'\G
# SHOW CREATE TABLE `isupipe`.`users`\G
# EXPLAIN /*!50100 PARTITIONS*/
SELECT * FROM users WHERE id = 1021\G
+-------+--------+--------------------------------------+--------+--------+--------+---------+
| COUNT | METHOD | URI | MIN | AVG | MAX | SUM |
+-------+--------+--------------------------------------+--------+--------+--------+---------+
| 578 | GET | /api/livestream/\d+/livecomment | 0.004 | 0.252 | 1.136 | 145.417 |
git grep -r '/api/livestream/:livestream_id/livecomment'
rsync-webapp-go/main.go:178: e.GET("/api/livestream/:livestream_id/livecomment", getLivecommentsHandler)
rsync-webapp-go/main.go:180: e.POST("/api/livestream/:livestream_id/livecomment", postLivecommentHandler)
rsync-webapp-go/main.go:188: e.POST("/api/livestream/:livestream_id/livecomment/:livecomment_id/report", reportLivecommentHandler)
自分用にtemp()等を記述しているため、行番号はオリジナルとはズレる
func getLivecommentsHandler(c echo.Context) error {
// ...
query := "SELECT * FROM livecomments WHERE livestream_id = ? ORDER BY created_at DESC"
if c.QueryParam("limit") != "" {
// ...
query += fmt.Sprintf(" LIMIT %d", limit)
}
livecommentModels := []LivecommentModel{}
err = tx.SelectContext(ctx, &livecommentModels, query, livestreamID)
if errors.Is(err, sql.ErrNoRows) { // 空なら空として返している
return c.JSON(http.StatusOK, []*Livecomment{})
}
livecomments := make([]Livecomment, len(livecommentModels))
for i := range livecommentModels {
livecomment, err := fillLivecommentResponse(ctx, tx, livecommentModels[i])
// ...
livecomments[i] = livecomment
}
// ...
}
limitの有無があるらしい
type Livecomment struct {
ID int64 `json:"id"`
User User `json:"user"`
Livestream Livestream `json:"livestream"`
Comment string `json:"comment"`
Tip int64 `json:"tip"`
CreatedAt int64 `json:"created_at"`
}
func fillLivecommentResponse(ctx context.Context, tx *sqlx.Tx, livecommentModel LivecommentModel) (Livecomment, error) {
commentOwnerModel := UserModel{}
if err := tx.GetContext(ctx, &commentOwnerModel, "SELECT * FROM users WHERE id = ?", livecommentModel.UserID); err != nil {
return Livecomment{}, err
}
commentOwner, err := fillUserResponse(ctx, tx, commentOwnerModel)
if err != nil {
return Livecomment{}, err
}
livestreamModel := LivestreamModel{}
if err := tx.GetContext(ctx, &livestreamModel, "SELECT * FROM livestreams WHERE id = ?", livecommentModel.LivestreamID); err != nil {
return Livecomment{}, err
}
livestream, err := fillLivestreamResponse(ctx, tx, livestreamModel)
if err != nil {
return Livecomment{}, err
}
livecomment := Livecomment{
ID: livecommentModel.ID,
User: commentOwner,
Livestream: livestream,
Comment: livecommentModel.Comment,
Tip: livecommentModel.Tip,
CreatedAt: livecommentModel.CreatedAt,
}
return livecomment, nil
}
type Livecomment struct {
ID int64
User type User struct { // usersテーブル
ID int64
}
Livestream type Livestream struct { // livestreamsテーブル
ID int64
}
}
1つのレスポンスを作るには、3テーブル必要
これを3回クエリ叩いている 1つでも失敗したら早期リターンしている→joinしたら良さそう
違った
type Livecomment struct {// livecommentsテーブル
ID int64 `json:"id"`
User User `json:"user"`
Livestream Livestream `json:"livestream"`
Comment string `json:"comment"`
Tip int64 `json:"tip"`
CreatedAt int64 `json:"created_at"`
}
type User struct { // usersテーブル
ID int64 `json:"id"`
Name string `json:"name"`
DisplayName string `json:"display_name,omitempty"`
Description string `json:"description,omitempty"`
Theme Theme `json:"theme,omitempty"`
IconHash string `json:"icon_hash,omitempty"`
}
type Theme struct { // themesテーブル
ID int64 `json:"id"`
DarkMode bool `json:"dark_mode"`
}
type Livestream struct {// livestreamsテーブル
ID int64 `json:"id"`
Owner User `json:"owner"`
Title string `json:"title"`
Description string `json:"description"`
PlaylistUrl string `json:"playlist_url"`
ThumbnailUrl string `json:"thumbnail_url"`
Tags []Tag `json:"tags"` // tagsは空のときもあり得ると考える
StartAt int64 `json:"start_at"`
EndAt int64 `json:"end_at"`
}
type Tag struct { // タグテーブル
ID int64 `json:"id"`
Name string `json:"name"`
}
これ見るとthemesテーブルとusersテーブルは1つにまとめても良さそうだけど、inner joinしたらいいだけなので、後半かも
issueに書き出しておく
どっちが早いんだろうか
とりあえず1でやる
そしてSQL記述する
select *
from livecomments
inner join users on users.id = livecomments.user_id
inner join themes on themes.user_id = users.id
inner join icons on icons.user_id = users.id
inner join livestreams on livestreams.id = livecomments.livestream_id
inner join users as owners on owners.id = livestreams.user_id
inner join themes as owner_themes on owner_themes.user_id = owners.id
inner join icons as owner_icons on owner_icons.user_id = owners.id
where livecomments.livestream_id = 7534
;
ハッシュ値も事前計算して画像はもう引っ張らないとかも後で入れようか
query := "SELECT * FROM livecomments WHERE livestream_id = ? ORDER BY created_at DESC"
livecomments.livestream_id
と livecomments.created_at desc
で複数index貼って良いかも
そして livestream_idだけのindexをワンちゃん外す(ただ、このへんは最後)
, livestream_owner_icons.id as "livestream_owner_icon_id"
, livestream_owner_icons.image as "livestream_owner_icon_image"
, (select GROUP_CONCAT(CONCAT(tags.id, ':', tags.name) SEPARATOR ',') from livestream_tags inner join tags on livestream_tags.tag_id = tags.id where livestream_tags.livestream_id = livecomments.livestream_id) as "livestream_tags"
from livecomments
みたいなサブクエリできるわ
select
livecomments.id as "livevcomment_id"
, livecomments.comment as "livecomment_comment"
, livecomments.tip as "livecomment_tip"
, livecomments.created_at as "livecomment_created_at"
, users.id as "user_id"
, users.name as "user_name"
, users.display_name as "user_display_name"
, users.description as "user_description"
, themes.id as "theme_id"
, themes.dark_mode as "theme_dark_mode"
, icons.id as "icon_id"
, icons.image as "icon_image"
, livestreams.id as "livestream_id"
, livestreams.title as "livestream_title"
, livestreams.description as "livestream_description"
, livestreams.playlist_url as "livestream_playlist_url"
, livestreams.thumbnail_url as "livestream_thumbnail_url"
, livestreams.start_at as "livestream_start_at"
, livestreams.end_at as "livestream_end_at"
, livestream_owners.id as "livestream_owner_id"
, livestream_owners.name as "livestream_owner_name"
, livestream_owners.display_name as "livestream_owner_display_name"
, livestream_owners.description as "livestream_owner_description"
, livestream_owner_themes.id as "livestream_owner_theme_id"
, livestream_owner_themes.dark_mode as "livestream_owner_theme_dark_mode"
, livestream_owner_icons.id as "livestream_owner_icon_id"
, livestream_owner_icons.image as "livestream_owner_icon_image"
, (select CONCAT('[', GROUP_CONCAT(CONCAT('{"', tags.id, '":"', tags.name, '"}') SEPARATOR ','), ']') from livestream_tags inner join tags on livestream_tags.tag_id = tags.id where livestream_tags.livestream_id = livecomments.livestream_id) as "livestream_tags"
from livecomments
inner join users on users.id = livecomments.user_id
inner join themes on themes.user_id = users.id
inner join icons on icons.user_id = users.id
inner join livestreams on livestreams.id = livecomments.livestream_id
inner join users as livestream_owners on livestream_owners.id = livestreams.user_id
inner join themes as livestream_owner_themes on livestream_owner_themes.user_id = livestream_owners.id
inner join icons as livestream_owner_icons on livestream_owner_icons.user_id = livestream_owners.id
where livecomments.livestream_id = 7534
コメントの分だけ、tagsが冗長になるけど、これでいいかな
ということから、もしかしたら2回のクエリに分けたほうがいいかもしれないけど、これでやる
サブクエリは以下のほうが楽ということに気づいた
, (select CONCAT('[', GROUP_CONCAT(CONCAT('{"id":', tags.id, ',"name":"', tags.name, '"}') SEPARATOR ','), ']') from livestream_tags inner join tags on livestream_tags.tag_id = tags.id where livestream_tags.livestream_id = livecomments.livestream_id) as "livestream_tags"
こんな感じ
[{"id":58,"name":"ペットと一緒"},{"id":34,"name":"夜ふかし"},{"id":102,"name":"サプライズ"},{"id":42,"name":"絵描き"},{"id":82,"name":"子育て"}]
icon持たないユーザー(レコードがない)も居た
leftjoinにしないといけない
続き
スコア:9975