clickhouse_schema.sql 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. -- 007_clickhouse.up.sql
  2. -- M7: ClickHouse schema for the deliveries archive.
  3. --
  4. -- ClickHouse is columnar and prefers wide tables with
  5. -- per-column compression. The schema mirrors the Postgres
  6. -- `deliveries` table one-to-one for v1; a future M7.5 can
  7. -- strip unused fields (e.g. drop the JSONB payload blob
  8. -- if we never query into it in CH).
  9. --
  10. -- The DDL below is designed to be runnable from the
  11. -- archiverd's first-run setup hook. It's also what the
  12. -- M7 smoke executes by hand via curl http://clickhouse:8123/.
  13. --
  14. -- Note on types:
  15. -- - `id` is BIGINT in Postgres (BIGSERIAL). In CH we
  16. -- keep BIGINT — CH's UInt64 is the closest match,
  17. -- but for an archive that doesn't reference id
  18. -- anywhere else, BIGINT is fine.
  19. -- - `payload` is JSONB in Postgres. We store it as a
  20. -- CH String. The Go side marshals to JSON text
  21. -- before INSERT. CH's JSON type is still experimental
  22. -- in 24.x; String is the safe choice.
  23. -- - `status` is a small enum ('pending','sent','failed','dlq').
  24. -- In CH we use LowCardinality(String) — the column
  25. -- takes ~0.5 bytes per row for the dictionary.
  26. CREATE DATABASE IF NOT EXISTS ba_archive;
  27. CREATE TABLE IF NOT EXISTS ba_archive.deliveries_archive (
  28. id BIGINT,
  29. alert_id String,
  30. company_id String,
  31. individual_id String,
  32. channel LowCardinality(String),
  33. target String,
  34. status LowCardinality(String),
  35. attempts UInt32,
  36. last_error String,
  37. payload String, -- raw JSON
  38. created_at DateTime64(3, 'UTC'),
  39. sent_at Nullable(DateTime64(3, 'UTC')),
  40. next_attempt_at Nullable(DateTime64(3, 'UTC')),
  41. -- The source postgres row's last-update marker. We
  42. -- set this to the wall-clock time at insert. Useful
  43. -- for "show me everything archived in the last 24h".
  44. archived_at DateTime DEFAULT now()
  45. ) ENGINE = MergeTree
  46. PARTITION BY toYYYYMM(created_at)
  47. ORDER BY (company_id, created_at, id)
  48. TTL toDateTime(created_at) + INTERVAL 365 DAY;
  49. -- (Optional) 1-year ClickHouse-side retention. We keep
  50. -- the data 365d in CH by default; the operator can extend
  51. -- or shorten via ALTER TABLE ... MODIFY TTL. Past 365d,
  52. -- CH drops the partition.
  53. -- A MATERIALIZED VIEW that aggregates per-company,
  54. -- per-day delivery counts. Used by M9 dashboards.
  55. CREATE MATERIALIZED VIEW IF NOT EXISTS
  56. ba_archive.deliveries_per_company_daily_mv
  57. ENGINE = SummingMergeTree
  58. PARTITION BY toYYYYMM(day)
  59. ORDER BY (company_id, day, channel, status)
  60. AS
  61. SELECT
  62. company_id,
  63. toDate(created_at) AS day,
  64. channel,
  65. status,
  66. count() AS n
  67. FROM ba_archive.deliveries_archive
  68. GROUP BY company_id, day, channel, status;