From 55065e2a9e0ce1ed75202bab2dd9ae3f350866e5 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Thu, 26 Aug 2021 23:47:53 +1200 Subject: [PATCH] 11x speed up of subscription page generation My 30 subscriptions now take 25 ms to generate, instead of around 280. Around 120 ms were saved by creating a database index. Around 120 ms were saved by pre-compiling the pug template for video description timestamps. The other changes in this commit produced slight improvements. --- api/subscriptions.js | 11 ++++------- utils/converters.js | 3 ++- utils/getuser.js | 5 ++++- utils/upgradedb.js | 5 +++++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/api/subscriptions.js b/api/subscriptions.js index 2c95004..6bb439b 100644 --- a/api/subscriptions.js +++ b/api/subscriptions.js @@ -16,18 +16,15 @@ module.exports = [ // trigger a background refresh, needed if they came back from being inactive refresher.skipWaiting() // get channels - const subscriptions = user.getSubscriptions() - const template = Array(subscriptions.length).fill("?").join(", ") - channels = db.prepare(`SELECT * FROM Channels WHERE ucid IN (${template}) ORDER BY name`).all(subscriptions) + channels = db.prepare(`SELECT Channels.* FROM Channels INNER JOIN Subscriptions ON Channels.ucid = Subscriptions.ucid WHERE token = ? ORDER BY name`).all(user.token) // get refreshed status - refreshed = db.prepare(`SELECT min(refreshed) as min, max(refreshed) as max, count(refreshed) as count FROM Channels WHERE ucid IN (${template})`).get(subscriptions) + refreshed = db.prepare(`SELECT min(refreshed) as min, max(refreshed) as max, count(refreshed) as count FROM Channels INNER JOIN Subscriptions ON Channels.ucid = Subscriptions.ucid WHERE token = ?`).get(user.token) // get watched videos const watchedVideos = user.getWatchedVideos() // get videos - if (subscriptions.length) { + if (channels.length) { hasSubscriptions = true - const template = Array(subscriptions.length).fill("?").join(", ") - videos = db.prepare(`SELECT * FROM Videos WHERE authorId IN (${template}) ORDER BY published DESC LIMIT 60`).all(subscriptions) + videos = db.prepare(`SELECT Videos.* FROM Videos INNER JOIN Subscriptions ON Videos.authorID = Subscriptions.ucid WHERE token = ? ORDER BY published DESC LIMIT 60`).all(user.token) .map(video => { video.publishedText = timeToPastText(video.published * 1000) video.watched = watchedVideos.includes(video.videoId) diff --git a/utils/converters.js b/utils/converters.js index d723cda..80358d8 100644 --- a/utils/converters.js +++ b/utils/converters.js @@ -58,6 +58,7 @@ function normaliseVideoInfo(video) { } } +const timeDisplayCompiled = pug.compile(`a(href=url data-clickable-timestamp=timeSeconds)= timeDisplay`) function rewriteVideoDescription(descriptionHtml, id) { // replace timestamps to clickable links and rewrite youtube links to stay on the instance instead of pointing to YouTube // test cases @@ -93,7 +94,7 @@ function rewriteVideoDescription(descriptionHtml, id) { params.set("t", timeURL) const url = "/watch?" + params - return pug.render(`a(href=url data-clickable-timestamp=timeSeconds)= timeDisplay`, {url, timeURL, timeDisplay, timeSeconds}) + return timeDisplayCompiled({url, timeURL, timeDisplay, timeSeconds}) }) return descriptionHtml diff --git a/utils/getuser.js b/utils/getuser.js index 7cbb7ef..d23fa0b 100644 --- a/utils/getuser.js +++ b/utils/getuser.js @@ -14,7 +14,10 @@ function getToken(req, responseHeaders) { return null } } - db.prepare("REPLACE INTO SeenTokens (token, seen) VALUES (?, ?)").run([token, Date.now()]) + db.prepare( + "INSERT INTO SeenTokens (token, seen) VALUES (?, ?)" + + " ON CONFLICT (token) DO UPDATE SET seen = excluded.seen" + ).run([token, Date.now()]) return token } diff --git a/utils/upgradedb.js b/utils/upgradedb.js index 78a7696..e12ae2d 100644 --- a/utils/upgradedb.js +++ b/utils/upgradedb.js @@ -58,6 +58,11 @@ const deltas = [ function() { db.prepare("ALTER TABLE Subscriptions ADD COLUMN channel_missing INTEGER DEFAULT 0") .run() + }, + // 9: add index Videos (authorID) + function() { + db.prepare("CREATE INDEX Videos_authorID ON Videos (authorID)") + .run() } ]