Skip to main content

Query Optimization

The Analytics Warehouse runs on ClickHouse, a columnar database. Queries behave differently than in a traditional relational database — a few habits make them dramatically faster.

Key principles

1. Always filter by date

Data is physically organized by time. A date filter lets ClickHouse skip whole chunks of history without reading them — and since the warehouse now serves full history (not just 3 months), date filters matter more than ever. Each table has one primary time column to filter on:

2. You don’t need to filter by company_id

Your user has a row policy that filters by your company automatically, and the data is sorted by company first — every query benefits from this without you adding anything.

3. Select only the columns you need

ClickHouse reads only the columns you mention. This matters most on wide text columns (text, content, ai_automator_instructions): leaving them out of a SELECT can cut a query’s cost by an order of magnitude.

4. Aggregate in the database, not in your tool

Pull answers, not raw rows. A GROUP BY over millions of rows returns in well under a second; downloading those millions of rows into a BI tool doesn’t.

5. Use the daily rollups when they fit

fact_campaign_daily and fact_agent_daily pre-compute the most common dashboard metrics. A dashboard over a rollup reads thousands of rows instead of millions.

6. Use LIMIT when exploring

JOIN tips

  • Join through ids, not names: session_id, agent_conversation_id, hsm_id — names are for display.
  • Put the small table on the right side of the JOIN — ClickHouse loads the right side into memory. Dimensions are always small; joining two big fact tables works best when both sides carry a date filter.
  • Include company_id in the join key when joining facts to dimensions (as the examples in this documentation do).

System limits

Your user runs with protection limits that keep the platform stable for everyone: If a query is cancelled by a limit:
  • Add or tighten the date filter (the fix in almost every case)
  • Drop unneeded columns — especially wide text columns
  • Aggregate with GROUP BY instead of pulling raw rows
  • Break very large extractions into month-sized chunks (see Incremental Sync for the pattern that avoids large extractions entirely)