optimize recordings/summary endpoint db query

replace strftime with integer arithmetic. increases speed by about 6x, especially noticeable for installs with long retention days
This commit is contained in:
Josh Hawkins 2026-03-09 17:28:53 -05:00
parent 9cbd80d981
commit 9b2bd14db6

View File

@ -1,5 +1,6 @@
"""Recording APIs.""" """Recording APIs."""
import datetime as dt
import logging import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from functools import reduce from functools import reduce
@ -97,45 +98,24 @@ def all_recordings_summary(
days: dict[str, bool] = {} days: dict[str, bool] = {}
for period_start, period_end, period_offset in dst_periods: for period_start, period_end, period_offset in dst_periods:
hours_offset = int(period_offset / 60 / 60) # Use integer division instead of strftime(datetime(...)) — orders of
minutes_offset = int(period_offset / 60 - hours_offset * 60) # magnitude cheaper per row and avoids a temp B-tree for GROUP BY.
period_hour_modifier = f"{hours_offset} hour" day_expr = ((Recordings.start_time + period_offset) / 86400).cast("int")
period_minute_modifier = f"{minutes_offset} minute"
period_query = ( period_query = (
Recordings.select( Recordings.select(day_expr.alias("day_idx"))
fn.strftime(
"%Y-%m-%d",
fn.datetime(
Recordings.start_time,
"unixepoch",
period_hour_modifier,
period_minute_modifier,
),
).alias("day")
)
.where( .where(
(Recordings.camera << camera_list) (Recordings.camera << camera_list)
& (Recordings.end_time >= period_start) & (Recordings.end_time >= period_start)
& (Recordings.start_time <= period_end) & (Recordings.start_time <= period_end)
) )
.group_by( .distinct()
fn.strftime(
"%Y-%m-%d",
fn.datetime(
Recordings.start_time,
"unixepoch",
period_hour_modifier,
period_minute_modifier,
),
)
)
.order_by(Recordings.start_time.desc())
.namedtuples() .namedtuples()
) )
for g in period_query: for g in period_query:
days[g.day] = True day_str = (dt.date(1970, 1, 1) + dt.timedelta(days=g.day_idx)).isoformat()
days[day_str] = True
return JSONResponse(content=dict(sorted(days.items()))) return JSONResponse(content=dict(sorted(days.items())))