Spaces:
Sleeping
Sleeping
File size: 6,805 Bytes
889ea3f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | -- ============================================================================
-- cache_schema.sql — Schema Tabella Cache per Supabase A
--
-- Eseguire su Supabase A (nodo analytics/cache) per creare la tabella cache
-- ============================================================================
-- Tabella Cache Entries
CREATE TABLE IF NOT EXISTS cache_entries (
id BIGSERIAL PRIMARY KEY,
cache_key VARCHAR(32) NOT NULL UNIQUE,
strategy VARCHAR(50) NOT NULL,
identifier TEXT NOT NULL,
value TEXT NOT NULL,
ttl_seconds INTEGER DEFAULT 3600,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- Indici per performance
CONSTRAINT cache_key_idx UNIQUE (cache_key),
CONSTRAINT strategy_idx ON strategy,
CONSTRAINT expires_at_idx ON expires_at
);
-- Indice su expires_at per pulizia automatica
CREATE INDEX IF NOT EXISTS idx_cache_expires_at ON cache_entries(expires_at);
-- Indice su strategy per query veloci per strategia
CREATE INDEX IF NOT EXISTS idx_cache_strategy ON cache_entries(strategy);
-- Indice composito per query veloci (strategy + identifier)
CREATE INDEX IF NOT EXISTS idx_cache_strategy_identifier ON cache_entries(strategy, identifier);
-- Tabella Statistiche Cache
CREATE TABLE IF NOT EXISTS cache_stats (
id BIGSERIAL PRIMARY KEY,
hits BIGINT DEFAULT 0,
misses BIGINT DEFAULT 0,
sets BIGINT DEFAULT 0,
deletes BIGINT DEFAULT 0,
evictions BIGINT DEFAULT 0,
recorded_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT cache_stats_pkey PRIMARY KEY (id)
);
-- Tabella Audit Cache (opzionale)
CREATE TABLE IF NOT EXISTS cache_audit (
id BIGSERIAL PRIMARY KEY,
action VARCHAR(50) NOT NULL, -- 'GET', 'SET', 'DELETE', 'EVICT'
strategy VARCHAR(50) NOT NULL,
identifier TEXT NOT NULL,
cache_key VARCHAR(32),
status VARCHAR(20) NOT NULL, -- 'HIT', 'MISS', 'SUCCESS', 'FAILURE'
duration_ms INTEGER,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indice su created_at per query audit veloci
CREATE INDEX IF NOT EXISTS idx_cache_audit_created_at ON cache_audit(created_at DESC);
-- Indice su action per filtrare per tipo operazione
CREATE INDEX IF NOT EXISTS idx_cache_audit_action ON cache_audit(action);
-- ============================================================================
-- Funzione: Pulizia automatica entry scaduti
-- ============================================================================
CREATE OR REPLACE FUNCTION cleanup_expired_cache()
RETURNS TABLE(deleted_count INTEGER) AS $$
BEGIN
DELETE FROM cache_entries WHERE expires_at < NOW();
RETURN QUERY SELECT COUNT(*)::INTEGER FROM cache_entries WHERE expires_at < NOW();
END;
$$ LANGUAGE plpgsql;
-- ============================================================================
-- Trigger: Aggiorna updated_at su UPDATE
-- ============================================================================
CREATE OR REPLACE FUNCTION update_cache_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER cache_entries_updated_at_trigger
BEFORE UPDATE ON cache_entries
FOR EACH ROW
EXECUTE FUNCTION update_cache_updated_at();
-- ============================================================================
-- View: Statistiche Cache Attuali
-- ============================================================================
CREATE OR REPLACE VIEW cache_stats_view AS
SELECT
COUNT(*) as total_entries,
COUNT(CASE WHEN expires_at > NOW() THEN 1 END) as valid_entries,
COUNT(CASE WHEN expires_at <= NOW() THEN 1 END) as expired_entries,
COUNT(DISTINCT strategy) as unique_strategies,
MIN(created_at) as oldest_entry,
MAX(created_at) as newest_entry,
AVG(ttl_seconds) as avg_ttl_seconds
FROM cache_entries;
-- ============================================================================
-- View: Hit Rate (ultimi 24 ore)
-- ============================================================================
CREATE OR REPLACE VIEW cache_hit_rate_24h AS
SELECT
COUNT(CASE WHEN status = 'HIT' THEN 1 END) as hits,
COUNT(CASE WHEN status = 'MISS' THEN 1 END) as misses,
COUNT(*) as total_requests,
ROUND(
COUNT(CASE WHEN status = 'HIT' THEN 1 END)::NUMERIC /
NULLIF(COUNT(*), 0) * 100,
2
) as hit_rate_percent
FROM cache_audit
WHERE created_at > NOW() - INTERVAL '24 hours';
-- ============================================================================
-- Policy RLS (Row Level Security) — Opzionale
-- ============================================================================
-- Abilita RLS sulla tabella cache_entries
ALTER TABLE cache_entries ENABLE ROW LEVEL SECURITY;
-- Policy: Tutti possono leggere cache (read-only per A)
CREATE POLICY "Allow read access to cache" ON cache_entries
FOR SELECT USING (true);
-- Policy: Solo service role può scrivere/modificare cache
CREATE POLICY "Allow write access to cache (service role only)" ON cache_entries
FOR INSERT WITH CHECK (current_user = 'postgres');
CREATE POLICY "Allow update access to cache (service role only)" ON cache_entries
FOR UPDATE USING (current_user = 'postgres');
CREATE POLICY "Allow delete access to cache (service role only)" ON cache_entries
FOR DELETE USING (current_user = 'postgres');
-- ============================================================================
-- Commenti Documentazione
-- ============================================================================
COMMENT ON TABLE cache_entries IS 'Archivio cache distribuito su Supabase A (read-heavy, non-critical)';
COMMENT ON COLUMN cache_entries.cache_key IS 'Chiave cache univoca (SHA256 hash di strategy:identifier)';
COMMENT ON COLUMN cache_entries.strategy IS 'Strategia cache: query, memory, embedding, conversation, analytics';
COMMENT ON COLUMN cache_entries.identifier IS 'Identificatore univoco per il valore (es. session_id, query_hash)';
COMMENT ON COLUMN cache_entries.value IS 'Valore memorizzato in cache (JSON serializzato)';
COMMENT ON COLUMN cache_entries.ttl_seconds IS 'Time-to-live in secondi (tempo di scadenza)';
COMMENT ON COLUMN cache_entries.expires_at IS 'Timestamp di scadenza (created_at + ttl_seconds)';
COMMENT ON TABLE cache_stats IS 'Statistiche aggregate del cache layer';
COMMENT ON TABLE cache_audit IS 'Audit log di tutte le operazioni cache (GET, SET, DELETE, EVICT)';
COMMENT ON FUNCTION cleanup_expired_cache() IS 'Rimuove entry scaduti dalla cache';
COMMENT ON VIEW cache_stats_view IS 'Statistiche attuali della cache (totale, valide, scadute, ecc.)';
COMMENT ON VIEW cache_hit_rate_24h IS 'Hit rate del cache nelle ultime 24 ore';
|