perf(cache): cache COUNT(*) result separately to avoid redundant queries
- Add TotalPublishedPosts cache key for reusing total count across pages - list_published_posts now checks total cache before running COUNT(*) - Add note to get_posts_by_tag about total = posts.len() assumption - Remove unused invalidate_total_published_posts helper
This commit is contained in:
parent
bd9053132b
commit
311ddbe204
@ -20,15 +20,21 @@ pub async fn list_published_posts(
|
||||
|
||||
let client = get_conn().await.map_err(AppError::db_conn)?;
|
||||
|
||||
// Get total count
|
||||
let count_row = client
|
||||
.query_one(
|
||||
"SELECT COUNT(*) FROM posts WHERE status = 'published' AND deleted_at IS NULL",
|
||||
&[],
|
||||
)
|
||||
.await
|
||||
.map_err(AppError::query)?;
|
||||
let total: i64 = count_row.get(0);
|
||||
// Get total count from cache or query
|
||||
let total = if let Some(cached_total) = crate::cache::get_total_published_posts().await {
|
||||
cached_total
|
||||
} else {
|
||||
let count_row = client
|
||||
.query_one(
|
||||
"SELECT COUNT(*) FROM posts WHERE status = 'published' AND deleted_at IS NULL",
|
||||
&[],
|
||||
)
|
||||
.await
|
||||
.map_err(AppError::query)?;
|
||||
let total: i64 = count_row.get(0);
|
||||
crate::cache::set_total_published_posts(total).await;
|
||||
total
|
||||
};
|
||||
|
||||
let offset = ((page - 1).max(0) as i64) * (per_page as i64);
|
||||
let limit = per_page as i64;
|
||||
@ -139,6 +145,9 @@ pub async fn get_posts_by_tag(tag_name: String) -> Result<PostListResponse, Serv
|
||||
posts.push(row_to_post_list(&client, row).await);
|
||||
}
|
||||
|
||||
// NOTE: total = posts.len() is correct because get_posts_by_tag
|
||||
// currently fetches ALL matching posts (no LIMIT/OFFSET).
|
||||
// If pagination is added later, switch to a proper COUNT(*) query.
|
||||
let total = posts.len() as i64;
|
||||
crate::cache::set_posts_by_tag(&tag_name, posts.clone(), total).await;
|
||||
Ok(PostListResponse { posts, total })
|
||||
|
||||
11
src/cache.rs
11
src/cache.rs
@ -31,6 +31,7 @@ const TTL_TAG_POSTS: Duration = Duration::from_secs(120);
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
pub enum CacheKey {
|
||||
PublishedPosts { page: i32, per_page: i32 },
|
||||
TotalPublishedPosts,
|
||||
AllTags,
|
||||
PostBySlug(String),
|
||||
PostsByTag(String),
|
||||
@ -109,6 +110,16 @@ pub async fn set_post_list(key: &CacheKey, posts: Vec<Post>, total: i64) {
|
||||
let _ = POST_LIST_CACHE.insert(key.clone(), (posts, total)).await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub async fn get_total_published_posts() -> Option<i64> {
|
||||
POST_LIST_CACHE.get(&CacheKey::TotalPublishedPosts).await.map(|(_, total)| total)
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub async fn set_total_published_posts(total: i64) {
|
||||
let _ = POST_LIST_CACHE.insert(CacheKey::TotalPublishedPosts, (vec![], total)).await;
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub async fn get_tag_list() -> Option<Vec<Tag>> {
|
||||
TAG_LIST_CACHE.get(&CacheKey::AllTags).await
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user