-- Persist blob sizes so storage-usage stats are a pure DB aggregate -- rather than a filesystem stat per page. Sizes are captured at write -- time (the crawler's put_stream already returns bytes written; uploads -- and covers know their byte length). Pre-existing rows carry NULL until -- the admin "backfill sizes" action stats their blobs. -- NULL = "size unknown / not yet backfilled". A measured value (even 0) -- is distinct from unknown, so a crawled-but-un-backfilled page is never -- mistaken for a genuinely empty one. SUM/AVG ignore NULL, so an -- un-backfilled library reports honest partial totals rather than zeros. ALTER TABLE pages ADD COLUMN size_bytes BIGINT; -- Nullable for the same reason, mirroring the nullable cover_image_path. ALTER TABLE mangas ADD COLUMN cover_size_bytes BIGINT; -- Covering index: makes the per-chapter / per-manga SUM(size_bytes) -- roll-ups (chapter list, leaderboards) index-only. The existing -- pages_chapter_idx (chapter_id, page_number) can serve the WHERE filter -- but not the SUM without heap visits. CREATE INDEX pages_chapter_size_idx ON pages (chapter_id) INCLUDE (size_bytes);