-- ============================================================ -- Phase 11: 全量物化视图 — 按月预计算所有慢函数 -- 数据导入后调用 analytics.refresh_all_monthly_views() 刷新 -- ============================================================ -- 1. mv_store_risk_rating_monthly DROP MATERIALIZED VIEW IF EXISTS analytics.mv_store_risk_rating_monthly; CREATE MATERIALIZED VIEW analytics.mv_store_risk_rating_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_store_risk_rating(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_risk_rating_month_store ON analytics.mv_store_risk_rating_monthly (month_start, store_code); CREATE INDEX idx_mv_risk_rating_month ON analytics.mv_store_risk_rating_monthly (month_start); -- ============================================================ -- 2. mv_store_platform_economics_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_store_platform_economics_monthly; CREATE MATERIALIZED VIEW analytics.mv_store_platform_economics_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_store_platform_economics(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_platform_econ_month_store ON analytics.mv_store_platform_economics_monthly (month_start, store_code); CREATE INDEX idx_mv_platform_econ_month ON analytics.mv_store_platform_economics_monthly (month_start); -- ============================================================ -- 3. mv_store_category_mix_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_store_category_mix_monthly; CREATE MATERIALIZED VIEW analytics.mv_store_category_mix_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_store_category_mix(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_cat_mix_month_store ON analytics.mv_store_category_mix_monthly (month_start, store_code); CREATE INDEX idx_mv_cat_mix_month ON analytics.mv_store_category_mix_monthly (month_start); -- ============================================================ -- 4. mv_store_member_opportunity_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_store_member_opportunity_monthly; CREATE MATERIALIZED VIEW analytics.mv_store_member_opportunity_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_store_member_opportunity(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_member_opp_month_store ON analytics.mv_store_member_opportunity_monthly (month_start, store_code); CREATE INDEX idx_mv_member_opp_month ON analytics.mv_store_member_opportunity_monthly (month_start); -- ============================================================ -- 5. mv_store_benchmark_composite_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_store_benchmark_composite_monthly; CREATE MATERIALIZED VIEW analytics.mv_store_benchmark_composite_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_store_benchmark_composite(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_benchmark_month_store ON analytics.mv_store_benchmark_composite_monthly (month_start, store_code); CREATE INDEX idx_mv_benchmark_month ON analytics.mv_store_benchmark_composite_monthly (month_start); -- ============================================================ -- 6. mv_store_deep_diagnosis_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_store_deep_diagnosis_monthly; CREATE MATERIALIZED VIEW analytics.mv_store_deep_diagnosis_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_store_deep_diagnosis(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_deep_diag_month_store ON analytics.mv_store_deep_diagnosis_monthly (month_start, store_code); CREATE INDEX idx_mv_deep_diag_month ON analytics.mv_store_deep_diagnosis_monthly (month_start); -- ============================================================ -- 7. mv_dish_basket_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_dish_basket_monthly; CREATE MATERIALIZED VIEW analytics.mv_dish_basket_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_dish_basket(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_dish_basket_month ON analytics.mv_dish_basket_monthly (month_start, store_code, bill_no); CREATE INDEX idx_mv_dish_basket_month_start ON analytics.mv_dish_basket_monthly (month_start); -- ============================================================ -- 8. mv_dish_store_summary_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_dish_store_summary_monthly; CREATE MATERIALIZED VIEW analytics.mv_dish_store_summary_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_dish_store_summary(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_dish_store_summary_month ON analytics.mv_dish_store_summary_monthly (month_start, store_code); CREATE INDEX idx_mv_dish_store_summary_month_start ON analytics.mv_dish_store_summary_monthly (month_start); -- ============================================================ -- 9. mv_store_theoretical_actual_cost_monthly -- ============================================================ DROP MATERIALIZED VIEW IF EXISTS analytics.mv_store_theoretical_actual_cost_monthly; CREATE MATERIALIZED VIEW analytics.mv_store_theoretical_actual_cost_monthly AS SELECT m.month_start::date AS month_start, r.* FROM generate_series( (SELECT date_trunc('month', min(closed_at))::date FROM analytics.bill_fact), (SELECT date_trunc('month', max(closed_at))::date FROM analytics.bill_fact), interval '1 month' ) AS m(month_start) CROSS JOIN LATERAL analytics.fn_store_theoretical_actual_cost(m.month_start::date) r; CREATE UNIQUE INDEX idx_mv_theor_actual_month_store ON analytics.mv_store_theoretical_actual_cost_monthly (month_start, store_code); CREATE INDEX idx_mv_theor_actual_month ON analytics.mv_store_theoretical_actual_cost_monthly (month_start); -- ============================================================ -- 刷新函数 — 数据导入后调用 -- ============================================================ CREATE OR REPLACE FUNCTION analytics.refresh_all_monthly_views() RETURNS void LANGUAGE plpgsql AS $function$ BEGIN REFRESH MATERIALIZED VIEW analytics.mv_dish_sku_summary_monthly; REFRESH MATERIALIZED VIEW analytics.mv_dish_sku_abc_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_risk_rating_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_platform_economics_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_category_mix_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_member_opportunity_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_benchmark_composite_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_deep_diagnosis_monthly; REFRESH MATERIALIZED VIEW analytics.mv_dish_basket_monthly; REFRESH MATERIALIZED VIEW analytics.mv_dish_store_summary_monthly; REFRESH MATERIALIZED VIEW analytics.mv_store_theoretical_actual_cost_monthly; END; $function$;