meta: run the 5 facet queries concurrently via asyncio.gather

/api/meta built the city/brand/dimension/manager/status option lists with five
sequential `await ch_query(...)` calls, so its latency was the sum of five
round-trips to ClickHouse. The queries are independent, and the frontend hits
/api/meta on every filter change, so this was 5x latency for no reason.

Wrap them in asyncio.gather so they fire in parallel; total time is now ~the
slowest single query plus overhead. Output verified identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
aaverbitskiy 2026-08-05 19:30:29 +00:00
parent 1f5b393675
commit 530bb4754e

45
main.py
View File

@ -1,3 +1,4 @@
import asyncio
import os
import httpx
from fastapi import FastAPI, Query
@ -159,26 +160,30 @@ async def meta(city: str = "", dimension: str = "", brand: str = "", manager: st
params = parse_filters(city, dimension, brand, manager, status, search, date_start, date_end)
hds = bool(params["date_start"])
hde = bool(params["date_end"])
cities = await ch_query(
f"SELECT DISTINCT city FROM default.pf_board WHERE {build_where(dimension=True, brand=True, manager=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(city) > 0 ORDER BY city",
params,
)
brands = await ch_query(
f"SELECT DISTINCT brand FROM default.pf_board WHERE {build_where(city=True, dimension=True, manager=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(brand) > 0 ORDER BY brand",
params,
)
dimensions = await ch_query(
f"SELECT DISTINCT dimension FROM default.pf_board WHERE {build_where(city=True, brand=True, manager=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(dimension) > 0 ORDER BY dimension",
params,
)
# manager is an Array(String) column — ARRAY JOIN to enumerate distinct names.
managers = await ch_query(
f"SELECT DISTINCT m AS manager FROM default.pf_board ARRAY JOIN manager AS m WHERE {build_where(city=True, dimension=True, brand=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(m) > 0 ORDER BY manager",
params,
)
statuses = await ch_query(
f"SELECT DISTINCT task_status FROM default.pf_board WHERE {build_where(city=True, dimension=True, brand=True, manager=True, search=True, date_start=hds, date_end=hde)} AND char_length(task_status) > 0 ORDER BY task_status",
params,
# The five facet lists are independent queries, so run them concurrently
# instead of awaiting one after another (5x latency on every filter change).
cities, brands, dimensions, managers, statuses = await asyncio.gather(
ch_query(
f"SELECT DISTINCT city FROM default.pf_board WHERE {build_where(dimension=True, brand=True, manager=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(city) > 0 ORDER BY city",
params,
),
ch_query(
f"SELECT DISTINCT brand FROM default.pf_board WHERE {build_where(city=True, dimension=True, manager=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(brand) > 0 ORDER BY brand",
params,
),
ch_query(
f"SELECT DISTINCT dimension FROM default.pf_board WHERE {build_where(city=True, brand=True, manager=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(dimension) > 0 ORDER BY dimension",
params,
),
# manager is an Array(String) column — ARRAY JOIN to enumerate distinct names.
ch_query(
f"SELECT DISTINCT m AS manager FROM default.pf_board ARRAY JOIN manager AS m WHERE {build_where(city=True, dimension=True, brand=True, status=True, search=True, date_start=hds, date_end=hde)} AND char_length(m) > 0 ORDER BY manager",
params,
),
ch_query(
f"SELECT DISTINCT task_status FROM default.pf_board WHERE {build_where(city=True, dimension=True, brand=True, manager=True, search=True, date_start=hds, date_end=hde)} AND char_length(task_status) > 0 ORDER BY task_status",
params,
),
)
return {
"cities": [r["city"] for r in cities],