Every room visit and every reconnection asks for the messages updated
since the page was rendered. That query filtered the room by updated_at
and sorted it by created_at, so SQLite walked every message in the room:
about 220-360 ms in a room of a million messages. An index on
(room_id, updated_at) finds the few updated messages directly.
Sorting on +created_at keeps SQLite on that index once messages are also
indexed by (room_id, created_at): with both, the planner otherwise walks
the room in creation order looking for updated rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JVFo3Lt9T8M5NR7KxVvsZ2
Previously we had to use structure.sql since schema.rb didn't have support for virtual tables that we needed for search. Since Campfire's release virtuals tables have been added to Rails, so there is no need to use structure.sql anymore