Demo · Federated SQL pushdown

Search in Turbopuffer.
Join in SQL.

Write one SQL query over your vector index. Chalk pushes the ranking, the filters and the limit into Turbopuffer as a single search, then joins the few rows that come back with everything else your query touches.

One question, five queries

A customer writes in: “I can't log in, the password reset email never shows up.” Each query below finds the helpdesk articles that answer it. Everything shown is recorded from a real run against a live Turbopuffer namespace: the plan before and after optimization, the request Turbopuffer received, and the rows it returned.

Nearest articles to the question

The ranking, sort and limit all fold into the scan. Turbopuffer runs one nearest-neighbor search and returns five rows.

SQL
SELECT id, title, product,
       tpuf_ann(vector, CAST([<embedding of the question>] AS FLOAT[256])) AS __score__
FROM helpdesk.articles
ORDER BY __score__ DESC
LIMIT 5
Request Turbopuffer received
{
  "rank_by": ["vector", "ANN", "<256 floats>"],
  "top_k": 5,
  "include_attributes": ["audience", "body", "product", "title", "updated_at", "views"]
}
Plan before optimizationwhat the SQL asks for
  1. Limit 5pushed down
  2. └Project id, title, product, __score__
  3. └Sort __score__ DESCpushed down
  4. └Project tpuf_ann(vector, q) AS __score__pushed down
  5. └Turbopuffer scan · helpdesk.articles
Plan after pushdownwhat ChalkSQL still runs
  1. Project id, title, product, __score__
  2. └Turbopuffer scan · helpdesk.articles
Results · 5 rows
idtitleproductdistance
1Reset a forgotten passwordauth0.240
2Password reset email never arrivedauth0.314
5Locked out after too many sign-in attemptsauth0.425
6Recover an account without access to two-factorauth0.553
23Mobile app keeps logging me outauth0.586

How pushdown works

A vector index is fast at one thing: finding the few best matches under a filter. Pushdown hands it exactly that job and keeps everything else in SQL, so a query never pulls the whole index across the network.

A namespace is a table

Register a Turbopuffer namespace with ChalkSQL and it becomes helpdesk.articles: its id, its vector, a __score__ column, and every attribute as a typed SQL column.

The optimizer pushes work down

Before the query runs, the planner folds the ranking, the filters Turbopuffer understands, the sort and the LIMIT into the scan, and turns them into one Turbopuffer query.

SQL does the rest

Whatever Turbopuffer cannot do, ChalkSQL does on the handful of rows that come back: predicates it has no operator for, joins against other sources, aggregates.

The code

A namespace, a query, one request

Register the namespace once, with the attributes you want as SQL columns. From then on it is a table like any other: query it, filter it, and join it with your features, your warehouse or a list of support queues.

The third tab is the whole of what crosses the network: one search, three filters, and a top_k of 3.

-- The ranking is selected as __score__ and ordered DESC with a LIMIT:
-- that is the shape the optimizer folds into one Turbopuffer search.
SELECT id, title, product,
       tpuf_ann(vector, CAST(:question_embedding AS FLOAT[256])) AS __score__
FROM helpdesk.articles
WHERE product = 'auth' AND audience = 'customer'
ORDER BY __score__ DESC
LIMIT 3

Writing queries that push down

Three rules cover every query on this page.

Rank, then order and limit

Select the ranking as __score__, order by __score__ DESC, and add a LIMIT. That becomes rank_by and top_k. For vector search the score is a cosine distance, so the best match has the smallest value.

Filters that push down

=, <>, <, <=, >, >= against a typed literal, NOT, LIKE and starts_with (as Turbopuffer glob filters), combined with AND. They join the same request as the ranking.

Everything else, after retrieval

Retrieve the top candidates in a subquery and filter or join them in the outer query. Turbopuffer still does the search; ChalkSQL only touches the rows it returned.

Query every source as one

Vector indexes, warehouses, databases and features, in one SQL query that sends each source only the work it does best. Talk to an engineer about your retrieval stack.