-- ============================================================================= -- 10_perf_indexes.sql — Migrations de performance (indexes + vues matérialisées) -- -- Ce fichier applique les optimisations de performance sur des tables existantes. -- Il est idempotent : les ADD INDEX / ADD PROJECTION échouent silencieusement -- si l'index existe déjà (IF NOT EXISTS non disponible pour les indexes, utiliser -- la commande IF NOT EXISTS en ClickHouse 24+, sinon ignorer les erreurs ALREADY_EXISTS). -- -- Usage : -- Pour une installation fraîche, ces optimisations sont déjà incluses dans les -- fichiers 04/05/06_*.sql. Ce fichier sert aux migrations d'instances existantes. -- -- clickhouse-client --multiquery < 10_perf_indexes.sql -- -- Sections : -- 1. ml_detected_anomalies — indexes de saut temporels et sémantiques -- 2. ml_all_scores — index de saut temporel -- 3. http_logs — bloom filter sur src_ip et ja4 -- 4. agg_host_ip_ja4_1h — projection per-IP pour les requêtes d'investigation -- ============================================================================= -- NOTE : PARTITION BY ne peut pas être ajouté via ALTER TABLE dans ClickHouse. -- Pour bénéficier du partitionnement journalier sur une table existante, il faut -- recréer la table et réinsérer les données : -- -- RENAME TABLE ja4_processing.ml_detected_anomalies -- TO ja4_processing.ml_detected_anomalies_old; -- (recréer avec 06_ml_tables.sql) -- INSERT INTO ja4_processing.ml_detected_anomalies -- SELECT * FROM ja4_processing.ml_detected_anomalies_old; -- DROP TABLE ja4_processing.ml_detected_anomalies_old; -- ============================================================================= -- 1. ml_detected_anomalies — indexes de saut -- ============================================================================= -- Index minmax sur detected_at : permet au moteur de sauter les granules -- (blocs de 8192 lignes) dont le min/max de detected_at est en dehors -- de la plage temporelle demandée (ex: WHERE detected_at >= now() - INTERVAL 24 HOUR). ALTER TABLE ja4_processing.ml_detected_anomalies ADD INDEX IF NOT EXISTS idx_detected_at detected_at TYPE minmax GRANULARITY 4; -- Index set(8) sur threat_level : stocke au maximum 8 valeurs distinctes -- par granule. Permet de sauter les granules qui ne contiennent pas la valeur -- filtrée (ex: WHERE threat_level = 'CRITICAL' skip les granules sans CRITICAL). ALTER TABLE ja4_processing.ml_detected_anomalies ADD INDEX IF NOT EXISTS idx_threat_level threat_level TYPE set(8) GRANULARITY 4; -- Index bloom_filter sur bot_name : skip des granules pour bot_name != '' -- et les filtres par nom exact (ex: WHERE bot_name = 'Googlebot'). ALTER TABLE ja4_processing.ml_detected_anomalies ADD INDEX IF NOT EXISTS idx_bot_name bot_name TYPE bloom_filter() GRANULARITY 4; -- Matérialiser les indexes sur les données existantes (opération asynchrone). -- ClickHouse traite ça en tâche de fond ; la table reste accessible en lecture. ALTER TABLE ja4_processing.ml_detected_anomalies MATERIALIZE INDEX idx_detected_at; ALTER TABLE ja4_processing.ml_detected_anomalies MATERIALIZE INDEX idx_threat_level; ALTER TABLE ja4_processing.ml_detected_anomalies MATERIALIZE INDEX idx_bot_name; -- ============================================================================= -- 2. ml_all_scores — index de saut temporel -- ============================================================================= ALTER TABLE ja4_processing.ml_all_scores ADD INDEX IF NOT EXISTS idx_detected_at detected_at TYPE minmax GRANULARITY 4; ALTER TABLE ja4_processing.ml_all_scores ADD INDEX IF NOT EXISTS idx_threat_level threat_level TYPE set(8) GRANULARITY 4; ALTER TABLE ja4_processing.ml_all_scores MATERIALIZE INDEX idx_detected_at; ALTER TABLE ja4_processing.ml_all_scores MATERIALIZE INDEX idx_threat_level; -- ============================================================================= -- 3. http_logs — bloom filter sur src_ip et ja4 -- -- http_logs est ORDER BY (time, src_ip, dst_ip, ja4). -- Les requêtes de type WHERE src_ip = X AND time >= ... ne peuvent pas utiliser -- l'index de tri efficacement (src_ip n'est pas en première position). -- Un bloom filter permet de sauter les granules qui ne contiennent pas l'IP -- recherchée, réduisant la quantité de données lues de ~90% en pratique. -- ============================================================================= ALTER TABLE ja4_logs.http_logs ADD INDEX IF NOT EXISTS idx_src_ip src_ip TYPE bloom_filter(0.01) GRANULARITY 4; ALTER TABLE ja4_logs.http_logs ADD INDEX IF NOT EXISTS idx_ja4 ja4 TYPE bloom_filter(0.01) GRANULARITY 4; ALTER TABLE ja4_logs.http_logs MATERIALIZE INDEX idx_src_ip; ALTER TABLE ja4_logs.http_logs MATERIALIZE INDEX idx_ja4; -- ============================================================================= -- 4. agg_host_ip_ja4_1h — projection per-IP -- -- ORDER BY actuel : (window_start, src_ip, ja4, host) -- → efficace pour les requêtes heatmap (GROUP BY window_start) -- → inefficace pour les requêtes d'investigation (WHERE src_ip = X) -- -- La projection stocke les données dans un ordre alternatif (src_ip en premier) -- et est utilisée automatiquement par ClickHouse quand src_ip est filtré. -- Coût : ~2× l'espace disque pour cette table (acceptable vu sa taille). -- ============================================================================= ALTER TABLE ja4_processing.agg_host_ip_ja4_1h ADD PROJECTION IF NOT EXISTS proj_by_ip ( SELECT * ORDER BY (src_ip, window_start, ja4, host) ); -- Matérialiser la projection sur les données existantes. ALTER TABLE ja4_processing.agg_host_ip_ja4_1h MATERIALIZE PROJECTION proj_by_ip;