Skip to content

Auto-index not used for simple eq(date) / eq(dispatchId) filters → heavy “graph run” time on param change #727

@evanheckert

Description

@evanheckert

Summary
When a route search param (date) changes, rendering stalls while useLiveQuery re-evaluates. In Chrome Performance (production build), most self time is inside tanstack-db’s internal query engine (shown as “graph run” / d2ts join). Filters are simple equalities on fields like date and dispatchId. From maintainer guidance, indexes are applied automatically, but the profile suggests the planner isn’t using an index path here.

What I measured (prod build)

Hook Name                                Total ms    Qty
useDispatchAssignedIds                   352.8449    39x
useSelectedInstallerSameDayAssignments     6.4560    89x
useCombinedInstallerIds                    4.3544    26x
useSelectedVehicleDispatch                 3.6657    26x
useVehicleAssignedIds                      3.6552    49x
useDispatchSidebarData                     0.6889     2x

Chrome Performance (Self Time) consistently shows big chunks in graph run / d2ts join during the update triggered by changing date.

The Slowest Query

const idVdSubquery = new Query()
  .from({ ind: installerDispatchCollection })
  .fullJoin({ vd: vehicleDispatchCollection }, ({ ind, vd }) => eq(ind.vehicleDispatchId, vd.id))
  .select(({ ind, vd }) => ({ installerDispatch: ind, vehicleDispatch: vd }))

export const useDispatchAssignedIds = (dateString: string, dispatchId?: string) => {
  console.time('useDispatchAssignedIds')
  const { data } = useLiveQuery(
    q =>
      q
        .from({ idVd: idVdSubquery })
        .where(({ idVd }) =>
          and(
            not(isUndefined(idVd.vehicleDispatch?.dispatchId)),
            eq(idVd.vehicleDispatch?.dispatchId, dispatchId),
            eq(idVd.vehicleDispatch?.date, dateString)
          )
        )
        .orderBy(({ idVd }) => idVd.installerDispatch?.id, 'asc')
        .select(({ idVd }) => ({
          installerDispatchId: idVd.installerDispatch?.id,
          vehicleDispatchId: idVd.vehicleDispatch?.id,
          vehicleId: idVd.vehicleDispatch?.vehicleId,
        })),
    [dateString, dispatchId]
  )
  console.timeEnd('useDispatchAssignedIds')
  return data
}

Expected

  • Equality filters on common fields (date, dispatchId) should use auto-indexes, keeping graph work small and updates snappy.
  • UI should not visibly stall on date changes when data is local.

Actual

  • Rendering hangs while graph work completes; most time is spent inside the engine (not React paint).
  • Behavior suggests an index is not being used for these equality filters.

Hypothesis

  • Planner/optimizer is missing an indexable path for certain query graph shapes (e.g., equality on date followed by joins), forcing expensive scans/joins. (per discussion on Discord)

Artifacts

  • Chrome Performance screenshots (Self Time view):
Image Image

What would help

  • Confirmation that these equality filters should hit an index in live queries.
  • If this is a planner miss, a fix or a temporary pattern to guarantee index usage (e.g., specific join order or “anchor” collection guidance).
  • A way to verify index usage (devtools, explain-like diagnostics, or logging flag), so we can self-check query shapes.

Why this matters
Switching from a few “big” queries + JS transforms to many useLiveQuerys reduced total compute time, but the UI still blocks on date changes. If the planner used the expected indexes here, the page should feel instant.

Collections (row counts)

customers_customer            538
dispatch_dispatch           3,539
dispatch_installerdispatch  6,125
dispatch_vehicle               13
dispatch_vehicledate        1,929
dispatch_vehicledispatch    3,118
people_customuser              34
projects_contract           1,591
projects_job                  894
projects_projectsite        1,016
projects_trip                  13
projects_workorder          2,785

Environment

{
    "@electric-sql/client": "^1.1.0",
    "@electric-sql/react": "^1.0.15",
    ...
    "@tanstack/electric-db-collection": "^0.1.38",
    "@tanstack/query-core": "^5.90.5",
    "@tanstack/query-db-collection": "^0.2.36",
    "@tanstack/react-db": "^0.1.36",
    "@tanstack/react-router": "^1.133.35",
    ...
    "zod": "^4.1.12"
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "vite": "^7.1.12",
    ...
    "babel-plugin-react-compiler": "^1.0.0",
}
  • Vite production build
  • React Compiler enabled (still has some manual useMemo/useCallback)
  • OS/Browser: Chrome (Performance panel traces)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions