Run the item page's count and the feed list's queries together (#346)
entry_page awaited the page's query and then its count, about 40 and 24 ms on /api/entries, the busiest route; feed_list awaited five independent queries in turn (entries, downloaded, unread, blocked, feeds), 59 ms of a 67 ms /api/feeds, with the pool's connections idle. Both now use tokio::try_join!. On SQLite they queue on its connection as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -521,22 +521,22 @@ impl Db {
|
||||
// Of this person's feeds only, as the unread count is: counting every item of every feed on
|
||||
// the server, 1534 feeds for someone reading 146, was 184-316 ms, 70% of the feed list's
|
||||
// time (#165). The Directory reads this for every feed's title and artwork, not a count.
|
||||
// Five queries that need nothing of each other, run at once: one after another they were
|
||||
// 59 ms of a 67 ms feed list, on a pool of idle connections (#346).
|
||||
let entries = counts(
|
||||
"entries",
|
||||
"SELECT e.feed_id, count(*) AS n FROM entries e
|
||||
JOIN subscriptions sub ON sub.user_id = $1 AND sub.feed_id = e.feed_id
|
||||
WHERE (CAST($2 AS TEXT) IS NULL OR e.feed_id = $2) GROUP BY e.feed_id",
|
||||
vec![user_id.into(), one()],
|
||||
)
|
||||
.await?;
|
||||
);
|
||||
let downloaded = counts(
|
||||
"downloaded",
|
||||
"SELECT x.feed_id, count(*) AS n FROM enclosures x
|
||||
JOIN subscriptions sub ON sub.user_id = $1 AND sub.feed_id = x.feed_id
|
||||
WHERE x.path IS NOT NULL AND (CAST($2 AS TEXT) IS NULL OR x.feed_id = $2) GROUP BY x.feed_id",
|
||||
vec![user_id.into(), one()],
|
||||
)
|
||||
.await?;
|
||||
);
|
||||
let unread = counts(
|
||||
"unread",
|
||||
"SELECT e.feed_id, count(*) AS n FROM entries e
|
||||
@@ -549,22 +549,26 @@ impl Db {
|
||||
WHERE h.user_id = $1 AND h.feed_id = e.feed_id AND h.guid = e.guid)
|
||||
GROUP BY e.feed_id",
|
||||
vec![user_id.into(), one()],
|
||||
)
|
||||
.await?;
|
||||
let mut blocked: HashMap<String, Vec<String>> = tracing::Instrument::instrument(
|
||||
);
|
||||
let blocked = tracing::Instrument::instrument(
|
||||
blocklists::Entity::find().filter(blocklists::Column::UserId.eq(user_id)).all(&self.orm),
|
||||
step("blocked"),
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|b| (b.feed_id, keywords(Some(b.words)).unwrap_or_default()))
|
||||
.collect();
|
||||
);
|
||||
let mut rows = feeds::Entity::find();
|
||||
if let Some(id) = only {
|
||||
rows = rows.filter(feeds::Column::Id.eq(id));
|
||||
}
|
||||
Ok(tracing::Instrument::instrument(rows.all(&self.orm), step("feeds"))
|
||||
.await?
|
||||
let rows = tracing::Instrument::instrument(rows.all(&self.orm), step("feeds"));
|
||||
let (entries, downloaded, unread, blocked, rows) = tokio::try_join!(
|
||||
entries,
|
||||
downloaded,
|
||||
unread,
|
||||
async { blocked.await.map_err(anyhow::Error::from) },
|
||||
async { rows.await.map_err(anyhow::Error::from) },
|
||||
)?;
|
||||
let mut blocked: HashMap<String, Vec<String>> =
|
||||
blocked.into_iter().map(|b| (b.feed_id, keywords(Some(b.words)).unwrap_or_default())).collect();
|
||||
Ok(rows
|
||||
.into_iter()
|
||||
.map(|f| {
|
||||
let id = f.id.clone();
|
||||
|
||||
Reference in New Issue
Block a user