Skip to content

fix(rows): keep row counters fresh and reduce count queries#2781

Open
hweihwang wants to merge 2 commits into
mainfrom
fix/451-rows-counter
Open

fix(rows): keep row counters fresh and reduce count queries#2781
hweihwang wants to merge 2 commits into
mainfrom
fix/451-rows-counter

Conversation

@hweihwang

@hweihwang hweihwang commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes stale row counters in Tables after row changes.

  • Update the active table/view counter immediately after row load, create, update, or delete.
  • Refresh affected sibling view counters after row changes, debounced per table.
  • Count filtered view rows directly in SQL instead of materializing all matching row IDs in PHP.
  • Batch table row counts when listing tables to avoid one count query per table.

Closes #451
Related: #725, #731

Performance impact

This should be a net improvement for counter-heavy paths:

  • Table list row counts go from one COUNT(*) query per table to one grouped COUNT(*) ... GROUP BY table_id query for all readable tables, chunked at 1000 IDs.
  • Filtered view row counts now return a scalar SQL COUNT(*); previously they loaded all matching row IDs into PHP and counted the array.
  • Row create/update/delete adds at most one debounced view-list refresh per table per 500ms burst, instead of requiring a full page reload for fresh counters.

Tests

  • Added unit coverage for countRowsForView() matching filtered findAll() results.
  • Added unit coverage for batched table row counts.
  • Added Playwright coverage for navigation table/view counters after adding a row.

@hweihwang hweihwang requested review from blizzz and enjeck as code owners June 30, 2026 17:17
@hweihwang hweihwang removed request for blizzz and enjeck June 30, 2026 17:28
@hweihwang hweihwang self-assigned this Jun 30, 2026
@hweihwang hweihwang force-pushed the fix/451-rows-counter branch from c4c972a to c652292 Compare July 1, 2026 08:52
@hweihwang hweihwang requested a review from enjeck July 2, 2026 08:36
@blizzz

blizzz commented Jul 2, 2026

Copy link
Copy Markdown
Member

Thanks for the fix! Which performance impact can we expect from this change?

hweihwang added 2 commits July 7, 2026 16:48
The navigation and dashboard row counters are read from the table/view
objects in the tables store, which were only refreshed on a full table
list reload. Row create/update/delete updated the loaded rows in the
data store but never the stored rowsCount, so counters stayed stale
until the page was reloaded.

Frontend: sync the active table/view rowsCount from the loaded rows
length after each row load/create/update/delete, and adjust the parent
table count by +/-1 when rows are created or deleted through a view.
Because a row change can also add or remove the row from any filtered
view of the same table - which the client cannot determine locally -
the affected views' counts are reloaded from the backend, debounced to
coalesce bursts of edits. A Playwright test covers the table and a
sibling view counter both updating after adding a row, without reload.

Backend: countRowsForView() fetched every matching row id into PHP and
counted the array. It now counts matching sleeves directly in SQL - a
view without filters reuses the cheap table count, and filtered views
run a single COUNT(*) reusing the existing filter expressions. Because
filters are applied as `sleeves.id IN (subselect)` the outer count is
never inflated and no GROUP BY is required.

Related to #451, #725, #731

Signed-off-by: Hoang Pham <hoangmaths96@gmail.com>
Listing tables enhanced each table individually, running one COUNT query
per table to populate its row counter. For a user with many tables this
is a classic N+1.

Fetch all table row counts in a single grouped query before the enhance
loop and pass the result into enhanceTable(). The per-table read-rows
permission gate is preserved (unreadable tables report 0, matching the
previous getRowsCount() fallback), and the single-table enhance path is
unchanged. Context tables are no longer enhanced twice.

This addresses the table side of the listing N+1. View counts still run
one query per view, as a cheap stored/cached view counter depends on
per-user and value-dependent filters and needs a separate design.

Related to #451

Signed-off-by: Hoang Pham <hoangmaths96@gmail.com>
@hweihwang hweihwang force-pushed the fix/451-rows-counter branch from c652292 to dd943b9 Compare July 7, 2026 09:48
@hweihwang

Copy link
Copy Markdown
Contributor Author

Thanks for the fix! Which performance impact can we expect from this change?

@blizzz Ah thanks. I expect this to be a net positive:

table counters: N per-table count queries become one grouped count query for readable tables.
view counters: filtered views now use SQL COUNT(*) instead of loading all matching row IDs into PHP.
row changes add only one debounced view-counter refresh per table burst, not a full reload.
So the extra refresh is small, and the backend count paths are cheaper than before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update rows counter

3 participants