Files
Oxicloud/migrations/20260625000000_files_user_size_index.sql
T
DioCrafts d7c6894c80 perf(quota): stop recomputing storage usage on every GET /api/auth/me
GET /api/auth/me ran a synchronous O(N) SUM(size) over all the user's
files plus an unconditional UPDATE of auth.users on every call — one of
the most frequently hit endpoints — adding per-request latency, DB write
load, dead tuples and WAL even when nothing changed.

- /api/auth/me now serves the cached storage_used_bytes column instead of
  recomputing it inline.
- New StorageUsageService::start_reconciliation_job runs a periodic sweep
  on the maintenance pool that keeps the cached value current for every
  mutation (uploads, deletes, trash), so freshness no longer depends on
  hitting /me. Interval via OXICLOUD_STORAGE_USAGE_RECONCILE_SECS (default
  600s, floored at 30s; first sweep deferred one interval to avoid boot load).
- update_storage_usage only writes when the value actually changes
  (IS DISTINCT FROM), so the sweep produces no dead tuple / WAL on no-ops.
- New covering partial index idx_files_user_size_active makes the usage
  SUM an index-only scan instead of a heap scan over all the user's files.

Also collapse the same pre-existing clippy collapsible_else_if in
carddav_handler that blocks the -D warnings gate on this base.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 01:13:58 +02:00

19 lines
948 B
SQL

-- Covering partial index for per-user storage-usage accounting.
--
-- The usage calculation is:
-- SELECT COALESCE(SUM(size), 0) FROM storage.files
-- WHERE user_id = $1 AND NOT is_trashed;
--
-- Without an index that carries `size`, this is a heap scan over every file
-- the user owns. This index lets PostgreSQL satisfy it with an index-only scan:
-- * keyed by user_id → only the target user's rows are visited
-- * INCLUDE (size) → the sum is read straight from the index
-- * WHERE NOT is_trashed → matches the query predicate exactly and keeps
-- the index small (trashed files are excluded)
--
-- Used by the per-upload usage update and the periodic background
-- reconciliation sweep (GET /api/auth/me no longer recomputes usage inline).
CREATE INDEX IF NOT EXISTS idx_files_user_size_active
ON storage.files (user_id) INCLUDE (size)
WHERE NOT is_trashed;