Commit 80185218 authored by Quentin Smith's avatar Quentin Smith

storage/db: optimize /uploads queries without query string

This uses a different query structure for ListUploads when the query
string is empty. On our production database, this reduces the query
time from ~5s to ~0.1s, which drastically improves the performance of
perf.golang.org.

Change-Id: I1f2bf97449858d1b06791dd352cc437dcbda1fac
Reviewed-on: https://go-review.googlesource.com/37168
Run-TryBot: Quentin Smith <quentin@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 5a6afbd2
......@@ -590,33 +590,37 @@ func (db *DB) ListUploads(q string, extraLabels []string, limit int) *UploadList
query += fmt.Sprintf(", (SELECT l%d.Value FROM RecordLabels l%d WHERE l%d.UploadID = j.UploadID AND Name = ? LIMIT 1)", i, i, i)
args = append(args, label)
}
query += " FROM (SELECT UploadID, COUNT(*) as rCount FROM "
sql, qArgs, err := parseQuery(q)
if err != nil {
ret.err = err
return ret
}
args = append(args, qArgs...)
for i, part := range sql {
if i > 0 {
query += " INNER JOIN "
if len(sql) == 0 {
// Optimize empty query.
query += " FROM (SELECT UploadID, (SELECT COUNT(*) FROM Records r WHERE r.UploadID = u.UploadID) AS rCount FROM Uploads u ORDER BY u.Day DESC, u.Seq DESC, u.UploadID DESC"
if limit != 0 {
query += fmt.Sprintf(" LIMIT %d", limit)
}
query += fmt.Sprintf("(%s) t%d", part, i)
if i > 0 {
query += " USING (UploadID, RecordID)"
query += ") j"
} else {
// Join individual queries.
query += " FROM (SELECT UploadID, COUNT(*) as rCount FROM "
args = append(args, qArgs...)
for i, part := range sql {
if i > 0 {
query += " INNER JOIN "
}
query += fmt.Sprintf("(%s) t%d", part, i)
if i > 0 {
query += " USING (UploadID, RecordID)"
}
}
}
if len(sql) > 0 {
query += " LEFT JOIN"
}
query += " Records r"
if len(sql) > 0 {
query += " USING (UploadID, RecordID)"
}
query += " GROUP BY UploadID) j LEFT JOIN Uploads u USING (UploadID) ORDER BY u.Day DESC, u.Seq DESC, u.UploadID DESC"
if limit != 0 {
query += fmt.Sprintf(" LIMIT %d", limit)
query += " LEFT JOIN Records r USING (UploadID, RecordID)"
query += " GROUP BY UploadID) j LEFT JOIN Uploads u USING (UploadID) ORDER BY u.Day DESC, u.Seq DESC, u.UploadID DESC"
if limit != 0 {
query += fmt.Sprintf(" LIMIT %d", limit)
}
}
ret.sqlQuery, ret.sqlArgs = query, args
......
......@@ -392,7 +392,10 @@ func TestListUploads(t *testing.T) {
for _, test := range tests {
t.Run(fmt.Sprintf("query=%s/limit=%d", test.query, test.limit), func(t *testing.T) {
r := db.ListUploads(test.query, test.extraLabels, test.limit)
defer r.Close()
defer func() {
t.Logf("r.Debug: %s", r.Debug())
r.Close()
}()
var have []result
for r.Next() {
ui := r.Info()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment