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: Russ Cox <rsc@golang.org>
diff --git a/storage/db/db.go b/storage/db/db.go
index 9cb7745..a53931e 100644
--- a/storage/db/db.go
+++ b/storage/db/db.go
@@ -590,33 +590,37 @@
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
diff --git a/storage/db/db_test.go b/storage/db/db_test.go
index 6101098..76b8adf 100644
--- a/storage/db/db_test.go
+++ b/storage/db/db_test.go
@@ -392,7 +392,10 @@
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()