perf(clickhouse): P1 — partition + skipping indexes sur ml_detected_anomalies, http_logs, agg_host_ip_ja4_1h
Problème : toutes les requêtes du dashboard WHERE detected_at >= now() - INTERVAL N
faisaient un full scan car ml_detected_anomalies avait ORDER BY (src_ip) sans
partition ni index temporel.
Changements :
- 06_ml_tables.sql :
* ml_detected_anomalies : PARTITION BY toYYYYMMDD(detected_at)
→ élagage de partitions journalières sur toutes les requêtes temporelles
* INDEX idx_detected_at (minmax) → skip des granules hors plage
* INDEX idx_threat_level set(8) → skip pour countIf(threat_level = ...)
* INDEX idx_bot_name bloom_filter → skip pour bot_name != ''
* ttl_only_drop_parts = 1 → TTL par suppression de partition entière
* ml_all_scores : même traitement (PARTITION BY + 2 indexes)
- 04_mv_http_logs.sql :
* http_logs : INDEX idx_src_ip bloom_filter(0.01)
→ les requêtes WHERE src_ip = X (analysis.py, variability.py) sautent
~90% des granules sans scanner toute la plage temporelle
* INDEX idx_ja4 bloom_filter(0.01) → idem pour filtres JA4
- 05_aggregation_tables.sql :
* agg_host_ip_ja4_1h : PROJECTION proj_by_ip ORDER BY (src_ip, window_start, ...)
→ investigation_summary.py et rotation.py (WHERE src_ip = X) utilisent
automatiquement la projection au lieu de scanner tous les window_start
- 10_perf_indexes.sql (nouveau) :
* Migration ALTER TABLE pour instances existantes
* ADD INDEX + MATERIALIZE INDEX pour les 4 tables
* ADD PROJECTION + MATERIALIZE PROJECTION pour agg_host_ip_ja4_1h
* Note : PARTITION BY sur table existante nécessite recréation (documenté)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@ -1,10 +1,25 @@
|
||||
-- =============================================================================
|
||||
-- 06_ml_tables.sql — ML detection results tables
|
||||
-- Source: bot_detector/deploy_views.sql sections 6-6b + deploy_schema.sql items 11-12
|
||||
--
|
||||
-- Optimisations de performance :
|
||||
-- - ml_detected_anomalies : PARTITION BY date → élagage de partitions sur
|
||||
-- les requêtes temporelles (WHERE detected_at >= now() - INTERVAL N DAY)
|
||||
-- - INDEX idx_detected_at (minmax) → skip des granules hors plage temporelle
|
||||
-- - INDEX idx_threat_level (set) → skip pour les filtres par niveau de menace
|
||||
-- - ml_all_scores : PARTITION BY date + INDEX identiques
|
||||
-- =============================================================================
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- ml_detected_anomalies — anomaly detections above threat threshold
|
||||
--
|
||||
-- Déduplication : ReplacingMergeTree(detected_at) sur ORDER BY (src_ip)
|
||||
-- → conserve la détection la plus récente par IP.
|
||||
-- PARTITION BY : élagage journalier (les requêtes 24h/7j ignorent les vieilles
|
||||
-- partitions sans lire aucune donnée).
|
||||
-- INDEX idx_detected_at : skip des granules 8192 lignes hors de la plage
|
||||
-- temporelle demandée (minmax = min/max par granule).
|
||||
-- INDEX idx_threat_level : skip pour countIf(threat_level = 'CRITICAL') etc.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS ja4_processing.ml_detected_anomalies
|
||||
(
|
||||
@ -32,15 +47,30 @@ CREATE TABLE IF NOT EXISTS ja4_processing.ml_detected_anomalies
|
||||
-- Anubis enrichment (deploy_schema.sql item 11)
|
||||
anubis_bot_name LowCardinality(String) DEFAULT '',
|
||||
anubis_bot_action LowCardinality(String) DEFAULT '',
|
||||
anubis_bot_category LowCardinality(String) DEFAULT ''
|
||||
anubis_bot_category LowCardinality(String) DEFAULT '',
|
||||
|
||||
-- Index de saut : skip des granules hors plage temporelle
|
||||
INDEX idx_detected_at detected_at TYPE minmax GRANULARITY 4,
|
||||
-- Index de saut : skip pour les filtres sur threat_level (CRITICAL/HIGH/...)
|
||||
INDEX idx_threat_level threat_level TYPE set(8) GRANULARITY 4,
|
||||
-- Index de saut : skip pour les filtres bot_name != ''
|
||||
INDEX idx_bot_name bot_name TYPE bloom_filter() GRANULARITY 4
|
||||
)
|
||||
ENGINE = ReplacingMergeTree(detected_at)
|
||||
PARTITION BY toYYYYMMDD(detected_at)
|
||||
ORDER BY (src_ip)
|
||||
TTL detected_at + INTERVAL 30 DAY;
|
||||
TTL detected_at + INTERVAL 30 DAY
|
||||
SETTINGS
|
||||
index_granularity = 8192,
|
||||
ttl_only_drop_parts = 1; -- supprime la partition entière à expiration (plus efficace)
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- ml_all_scores — all classifications (no threshold, for observability)
|
||||
--
|
||||
-- PARTITION BY date : TTL de 3 jours → les partitions expirées sont supprimées
|
||||
-- entièrement sans avoir à lire chaque granule (ttl_only_drop_parts).
|
||||
-- INDEX idx_detected_at : idem ml_detected_anomalies.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS ja4_processing.ml_all_scores
|
||||
(
|
||||
@ -67,12 +97,18 @@ CREATE TABLE IF NOT EXISTS ja4_processing.ml_all_scores
|
||||
-- Anubis enrichment (deploy_schema.sql item 12)
|
||||
anubis_bot_name LowCardinality(String) DEFAULT '',
|
||||
anubis_bot_action LowCardinality(String) DEFAULT '',
|
||||
anubis_bot_category LowCardinality(String) DEFAULT ''
|
||||
anubis_bot_category LowCardinality(String) DEFAULT '',
|
||||
|
||||
INDEX idx_detected_at detected_at TYPE minmax GRANULARITY 4,
|
||||
INDEX idx_threat_level threat_level TYPE set(8) GRANULARITY 4
|
||||
)
|
||||
ENGINE = ReplacingMergeTree(detected_at)
|
||||
PARTITION BY toYYYYMMDD(window_start)
|
||||
ORDER BY (window_start, src_ip, ja4, host, model_name)
|
||||
TTL window_start + INTERVAL 3 DAY
|
||||
SETTINGS index_granularity = 8192;
|
||||
SETTINGS
|
||||
index_granularity = 8192,
|
||||
ttl_only_drop_parts = 1;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user