diff --git a/db/routines/R__088_fn_forecast_pv_slots_range_canonical_ab.sql b/db/routines/R__088_fn_forecast_pv_slots_range_canonical_ab.sql index d777ef7..c07f2a2 100644 --- a/db/routines/R__088_fn_forecast_pv_slots_range_canonical_ab.sql +++ b/db/routines/R__088_fn_forecast_pv_slots_range_canonical_ab.sql @@ -31,7 +31,21 @@ set work_mem = '64MB' as $fn$ declare v_result jsonb; + v_rolling_factor numeric; begin + -- Rolling faktor JEDNOU do proměnné: jako inlinovaná CTE (single-ref) se + -- fn_pv_forecast_correction_factor vyhodnocovala per výstupní řádek + -- (~300× ≈ 570k buffers / ~4 s — skutečná příčina pomalosti, ne plan cache). + v_rolling_factor := coalesce( + (ems.fn_pv_forecast_correction_factor( + p_site_id, + (p_now - (p_factor_window_h::text || ' hours')::interval)::timestamptz, + p_now, + p_factor_min_clamp, + p_factor_max_clamp + )->>'correction_factor')::numeric, + 1.0 + ); -- PG 18 cachuje plán SQL/plpgsql statementů s parametry → generický plán -- (4.5–9 s / 600k buffers); force_custom_plan na funkci nepomohl. Execute -- s literály vynutí čerstvý plán dle skutečných hodnot: 0.4 s / 34k buffers. @@ -70,20 +84,6 @@ begin from slot_spine s cross join tz t ), - factor_raw as ( - select ems.fn_pv_forecast_correction_factor( - %1$s, - (%4$L::timestamptz - (%9$s::text || ' hours')::interval)::timestamptz, - %4$L::timestamptz, - %10$s, - %11$s - ) as j - ), - factor as ( - select - coalesce((j->>'correction_factor')::numeric, 1.0::numeric) as rolling_factor - from factor_raw - ), profile as ( select ems.fn_pv_forecast_delta_profile_cached( %1$s, @@ -194,18 +194,17 @@ begin ab.pv_b_forecast_raw_w, ab.pv_a_forecast_delta_w, ab.pv_b_forecast_delta_w, - f.rolling_factor, + %13$s::numeric as rolling_factor, case when ab.interval_start < b.now_slot then 1.0::numeric - when %12$s <= 0 then f.rolling_factor + when %12$s <= 0 then %13$s::numeric else case when ((extract(epoch from (ab.interval_start - b.now_slot)) / 900)::int) >= %12$s then 1.0::numeric - else (1.0::numeric + (f.rolling_factor - 1.0::numeric) * (1.0::numeric - ((extract(epoch from (ab.interval_start - b.now_slot)) / 900)::numeric / %12$s::numeric))) + else (1.0::numeric + (%13$s::numeric - 1.0::numeric) * (1.0::numeric - ((extract(epoch from (ab.interval_start - b.now_slot)) / 900)::numeric / %12$s::numeric))) end end as rolling_effective_factor from fc_ab ab - cross join factor f cross join bounds b ) select coalesce( @@ -242,7 +241,8 @@ $q$, p_factor_window_h, p_factor_min_clamp, p_factor_max_clamp, - p_decay_slots + p_decay_slots, + v_rolling_factor ) into v_result; return coalesce(v_result, '[]'::jsonb); end;