perf: denormalize media_sort_date + pre-scale video thumbs
Schema (media_sort_date denormalization): - Add media_sort_date column to storage.files with DEFAULT created_at - Add trigger sync_media_sort_date: when file_metadata is upserted, copies COALESCE(captured_at, created_at) into files.media_sort_date - Add partial index idx_files_media_timeline on (user_id, media_sort_date DESC) WHERE NOT is_trashed AND media type -- enables Index Scan + Limit (no Sort) - copy_folder_tree now copies media_sort_date for copied files - Remove dead idx_file_metadata_captured (no longer needed) Query optimization (list_media_files): - Rewrite to use fi.media_sort_date instead of COALESCE(fm.captured_at,...) - Eliminates LEFT JOIN file_metadata -- one fewer table touch - Plan: Limit to Index Scan O(LIMIT) instead of Sort O(N) Video thumbnail pre-scaling (client + server): - JS: pre-scale canvas to max 400px before toBlob -- 22x less RAM, 15x less BW - Rust: fast-path in store_external_thumbnail -- if payload is already WebP with dims within max_dim, store as-is (zero decode, zero encode)
This commit is contained in:
@@ -165,6 +165,12 @@ impl FileBlobReadRepository {
|
||||
///
|
||||
/// Returns `(Vec<File>, Vec<i64>)` where the second vec contains the
|
||||
/// `sort_date` epoch for each file (used as pagination cursor).
|
||||
///
|
||||
/// Uses the denormalised `media_sort_date` column (synced from
|
||||
/// `file_metadata.captured_at` by trigger) so no JOIN with
|
||||
/// `file_metadata` is needed. The partial index
|
||||
/// `idx_files_media_timeline` covers the full query: filter + ORDER BY
|
||||
/// in a single Index Scan — O(LIMIT) not O(N).
|
||||
pub async fn list_media_files(
|
||||
&self,
|
||||
owner_id: Uuid,
|
||||
@@ -178,16 +184,15 @@ impl FileBlobReadRepository {
|
||||
EXTRACT(EPOCH FROM fi.created_at)::bigint,
|
||||
EXTRACT(EPOCH FROM fi.updated_at)::bigint,
|
||||
fi.user_id,
|
||||
EXTRACT(EPOCH FROM COALESCE(fm.captured_at, fi.created_at))::bigint AS sort_date
|
||||
EXTRACT(EPOCH FROM fi.media_sort_date)::bigint AS sort_date
|
||||
FROM storage.files fi
|
||||
LEFT JOIN storage.folders fo ON fo.id = fi.folder_id
|
||||
LEFT JOIN storage.file_metadata fm ON fm.file_id = fi.id
|
||||
WHERE fi.user_id = $1
|
||||
AND NOT fi.is_trashed
|
||||
AND (fi.mime_type LIKE 'image/%' OR fi.mime_type LIKE 'video/%')
|
||||
AND ($2::bigint IS NULL
|
||||
OR EXTRACT(EPOCH FROM COALESCE(fm.captured_at, fi.created_at))::bigint < $2::bigint)
|
||||
ORDER BY COALESCE(fm.captured_at, fi.created_at) DESC
|
||||
OR EXTRACT(EPOCH FROM fi.media_sort_date)::bigint < $2::bigint)
|
||||
ORDER BY fi.media_sort_date DESC
|
||||
LIMIT $3
|
||||
"#,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user