82 lines
2.9 KiB
MySQL
82 lines
2.9 KiB
MySQL
|
|
-- Analytics Database Initialization (TimescaleDB)
|
||
|
|
|
||
|
|
-- Enable extensions
|
||
|
|
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;
|
||
|
|
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
|
||
|
|
|
||
|
|
CREATE SCHEMA IF NOT EXISTS analytics;
|
||
|
|
|
||
|
|
-- Content views (hypertable)
|
||
|
|
CREATE TABLE IF NOT EXISTS analytics.content_views (
|
||
|
|
time TIMESTAMPTZ NOT NULL,
|
||
|
|
content_id UUID NOT NULL,
|
||
|
|
content_type VARCHAR(50) NOT NULL,
|
||
|
|
user_id UUID,
|
||
|
|
session_id VARCHAR(255),
|
||
|
|
referrer TEXT,
|
||
|
|
user_agent TEXT,
|
||
|
|
country VARCHAR(2),
|
||
|
|
device_type VARCHAR(20)
|
||
|
|
);
|
||
|
|
SELECT create_hypertable('analytics.content_views', 'time', if_not_exists => TRUE);
|
||
|
|
|
||
|
|
-- Engagement metrics (hypertable)
|
||
|
|
CREATE TABLE IF NOT EXISTS analytics.engagement_metrics (
|
||
|
|
time TIMESTAMPTZ NOT NULL,
|
||
|
|
content_id UUID NOT NULL,
|
||
|
|
metric_type VARCHAR(50) NOT NULL,
|
||
|
|
value DECIMAL(12, 4) NOT NULL,
|
||
|
|
metadata JSONB DEFAULT '{}'
|
||
|
|
);
|
||
|
|
SELECT create_hypertable('analytics.engagement_metrics', 'time', if_not_exists => TRUE);
|
||
|
|
|
||
|
|
-- Revenue metrics (hypertable)
|
||
|
|
CREATE TABLE IF NOT EXISTS analytics.revenue_metrics (
|
||
|
|
time TIMESTAMPTZ NOT NULL,
|
||
|
|
creator_id UUID NOT NULL,
|
||
|
|
transaction_type VARCHAR(50) NOT NULL,
|
||
|
|
gross_amount DECIMAL(12, 2) NOT NULL,
|
||
|
|
net_amount DECIMAL(12, 2) NOT NULL,
|
||
|
|
platform_fee DECIMAL(12, 2) NOT NULL,
|
||
|
|
currency VARCHAR(3) DEFAULT 'USD'
|
||
|
|
);
|
||
|
|
SELECT create_hypertable('analytics.revenue_metrics', 'time', if_not_exists => TRUE);
|
||
|
|
|
||
|
|
-- Dashboard snapshots
|
||
|
|
CREATE TABLE IF NOT EXISTS analytics.dashboard_snapshots (
|
||
|
|
id SERIAL PRIMARY KEY,
|
||
|
|
snapshot_type VARCHAR(50) NOT NULL,
|
||
|
|
period VARCHAR(20) NOT NULL,
|
||
|
|
data JSONB NOT NULL,
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
||
|
|
);
|
||
|
|
|
||
|
|
-- Continuous aggregates for common queries
|
||
|
|
CREATE MATERIALIZED VIEW IF NOT EXISTS analytics.hourly_views
|
||
|
|
WITH (timescaledb.continuous) AS
|
||
|
|
SELECT
|
||
|
|
time_bucket('1 hour', time) AS bucket,
|
||
|
|
content_type,
|
||
|
|
COUNT(*) as view_count,
|
||
|
|
COUNT(DISTINCT user_id) as unique_users
|
||
|
|
FROM analytics.content_views
|
||
|
|
GROUP BY bucket, content_type
|
||
|
|
WITH NO DATA;
|
||
|
|
|
||
|
|
-- Compression policy (compress data older than 7 days)
|
||
|
|
SELECT add_compression_policy('analytics.content_views', INTERVAL '7 days', if_not_exists => TRUE);
|
||
|
|
SELECT add_compression_policy('analytics.engagement_metrics', INTERVAL '7 days', if_not_exists => TRUE);
|
||
|
|
SELECT add_compression_policy('analytics.revenue_metrics', INTERVAL '7 days', if_not_exists => TRUE);
|
||
|
|
|
||
|
|
-- Indexes
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_views_content ON analytics.content_views(content_id, time DESC);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_engagement_content ON analytics.engagement_metrics(content_id, time DESC);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_revenue_creator ON analytics.revenue_metrics(creator_id, time DESC);
|
||
|
|
|
||
|
|
-- Permissions
|
||
|
|
GRANT ALL PRIVILEGES ON SCHEMA analytics TO lilith;
|
||
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA analytics TO lilith;
|
||
|
|
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA analytics TO lilith;
|
||
|
|
|
||
|
|
DO $$ BEGIN RAISE NOTICE 'Analytics database initialized with TimescaleDB'; END $$;
|