-- Normalized source tables (as produced by Third-Normal-Form)
-- customers (customer_id PK, customer_city)
-- orders (order_id PK, customer_id FK, order_total DECIMAL, created_at)
-- Technique 1: redundant column, kept in sync with a trigger.
-- Adding customer_city directly to orders avoids a JOIN on every order
-- listing query; a trigger keeps it current if a customer's city changes.
ALTER TABLE orders ADD COLUMN customer_city VARCHAR(80) NULL;
DELIMITER $$
CREATE TRIGGER trg_customers_city_sync
AFTER UPDATE ON customers
FOR EACH ROW
BEGIN
IF NOT (OLD.customer_city <=> NEW.customer_city) THEN
UPDATE orders
SET customer_city = NEW.customer_city
WHERE customer_id = NEW.customer_id;
END IF;
END$$
DELIMITER ;
-- Technique 2: summary/rollup table, refreshed on a schedule instead of
-- a materialized view (MySQL has no native equivalent).
CREATE TABLE daily_sales_summary (
sale_date DATE PRIMARY KEY,
order_count INT UNSIGNED NOT NULL,
total_revenue DECIMAL(12,2) NOT NULL
) ENGINE=InnoDB;
SET GLOBAL event_scheduler = ON;
DELIMITER $$
CREATE EVENT ev_refresh_daily_sales_summary
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
REPLACE INTO daily_sales_summary (sale_date, order_count, total_revenue)
SELECT DATE(created_at), COUNT(*), SUM(order_total)
FROM orders
WHERE created_at >= CURRENT_DATE - INTERVAL 2 DAY
GROUP BY DATE(created_at);
END$$
DELIMITER ;
-- A dashboard reads the precomputed table directly instead of aggregating
-- millions of order rows on every page load:
SELECT sale_date, order_count, total_revenue
FROM daily_sales_summary
ORDER BY sale_date DESC
LIMIT 30;
-- Normalized source tables (as produced by Third-Normal-Form)
-- customers (customer_id PK, customer_city)
-- orders (order_id PK, customer_id FK, order_total DECIMAL, created_at)
-- Technique 1: redundant column, kept in sync with a trigger.
-- Adding customer_city directly to orders avoids a JOIN on every order
-- listing query; a trigger keeps it current if a customer's city changes.
ALTER TABLE orders ADD COLUMN customer_city VARCHAR(80) NULL;
DELIMITER $$
CREATE TRIGGER trg_customers_city_sync
AFTER UPDATE ON customers
FOR EACH ROW
BEGIN
IF NOT (OLD.customer_city <=> NEW.customer_city) THEN
UPDATE orders
SET customer_city = NEW.customer_city
WHERE customer_id = NEW.customer_id;
END IF;
END$$
DELIMITER ;
-- Technique 2: summary/rollup table, refreshed on a schedule instead of
-- a materialized view (MySQL has no native equivalent).
CREATE TABLE daily_sales_summary (
sale_date DATE PRIMARY KEY,
order_count INT UNSIGNED NOT NULL,
total_revenue DECIMAL(12,2) NOT NULL
) ENGINE=InnoDB;
SET GLOBAL event_scheduler = ON;
DELIMITER $$
CREATE EVENT ev_refresh_daily_sales_summary
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
REPLACE INTO daily_sales_summary (sale_date, order_count, total_revenue)
SELECT DATE(created_at), COUNT(*), SUM(order_total)
FROM orders
WHERE created_at >= CURRENT_DATE - INTERVAL 2 DAY
GROUP BY DATE(created_at);
END$$
DELIMITER ;
-- A dashboard reads the precomputed table directly instead of aggregating
-- millions of order rows on every page load:
SELECT sale_date, order_count, total_revenue
FROM daily_sales_summary
ORDER BY sale_date DESC
LIMIT 30;