examples · ask · 2 / 6
2. Narrow with a schemas hint
← Ask exampleswhat this does
Same endpoint as the simple count, but the body now includes a "schemas" array. The compiler only considers the schemas you list - it never has to disambiguate against schemas in other namespaces.
when to use it
- You know which table the question is about - typical for app code where the surface is constrained.
- You have multiple namespaces in the same tenant and the same noun appears in more than one (
crm.customersvsshop.customers). - You're in a hot path and want compile cost to be a function of N schemas you control, not the whole tenant catalog.
The hint is included in the plan-cache key. Two calls with the same question but different schemas lists are different cache entries.
the schema
Register this once with POST /v1/tenants/:t/schemas.
namespace = "shop"
table = "customers"
primary_key = ["id"]
[[columns]]
name = "id"
ty = "str"
required = true
[[columns]]
name = "email"
ty = "str"
[[columns]]
name = "tier"
ty = "str"
[[indexes]]
name = "by_tier"
columns = ["tier"] seed data
# Seed customers across two tiers so the count below is non-trivial.
curl -X POST "https://$OC_HOST/v1/tenants/$OC_TENANT/rows/shop.customers/_batch" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '[
{ "id": "c_1", "email": "alice@example.com", "tier": "gold" },
{ "id": "c_2", "email": "bob@example.com", "tier": "silver" },
{ "id": "c_3", "email": "carol@example.com", "tier": "gold" },
{ "id": "c_4", "email": "dan@example.com", "tier": "silver" }
]' the request
POST /v1/tenants/:t/ask
curl -X POST "https://$OC_HOST/v1/tenants/$OC_TENANT/ask" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"nl": "how many gold-tier customers do I have?",
"schemas": ["shop.customers"]
}'result = db.ask(
"how many gold-tier customers do I have?",
schemas=["shop.customers"],
)
print(result["rows"], result["cache"])const result = await db.ask(
"how many gold-tier customers do I have?",
{ schemas: ["shop.customers"] }
);
console.log(result.rows, result.cache);result, err := db.Ask(ctx,
"how many gold-tier customers do I have?",
"shop.customers", // variadic schemas
)
if err != nil { /* handle */ }
fmt.Println(result.Rows, result.Cache) what you get back
{
"rows": [
{ "count": 2 }
],
"cache": "miss"
}
The shape is the same as the unhinted call - rows and cache. The difference is that the compiler walked one schema, not the whole tenant.
how it works
- The
schemaslist is part of the cache key - same question, different schemas list, different entry. - The compiler sees only the listed schemas in its catalog. Tables in other namespaces are invisible for this call.
- Recognising "gold-tier" hits the
tiercolumn. Because there's aby_tierindex, the plan becomesAggregate(count) → IndexScan(tier = "gold"). - Fewer schemas = a smaller compile prompt and a smaller search space for join planning, so first-call latency drops.
common mistakes
- Listing only one side of a join. If the question implies a join across two schemas, both must be in the
schemaslist. Otherwise the compiler can't see the relation and falls back tono_plan_compiled. - Bare table name without namespace. Schemas are addressed as
namespace.table."customers"alone returns400 unknown_schema. - Expecting it to change rows. The hint changes which plans the compiler considers, not the results. If the hint is satisfiable, you get the same answer as the unhinted call - just compiled faster.