Writing · Architecture decision
Schema-on-read vs schema-on-write. The $2.7M question.
Splunk's schema-on-read architecture stores raw events with minimal processing, applying structure only at query time through regex-based field extraction. This creates a repeated parsing problem: every search re-executes extraction logic, compounding compute costs for dashboards and correlation rules that query the same data hundreds of times daily. At 1 TB/day ingestion, this repeated parsing costs roughly $31,000 per month versus schema-on-write alternatives at $8,000–12,000 for equivalent query performance. But schema-on-read's flexibility proves essential for security operations managing 100+ diverse data sources where field name variations, new log formats, and retroactive field extraction during investigations provide irreplaceable operational value.
The repeated parsing problem
How Splunk's schema-on-read actually works.
Splunk stores raw events essentially unprocessed in compressed journal files within time-bounded buckets
(hot/warm/cold storage tiers). During indexing, Splunk extracts only five default fields:
_time, host, source, sourcetype, and
index.
TSIDX files associate keywords with event locations, enabling fast keyword-based filtering. But
structured field queries (user_id=alice, status_code=404,
source_ip=192.168.1.1) must parse raw text on every search using regex-based field
extraction rules.
An authentication log event, raw storage:
2024-01-15T14:23:47Z auth_server user=alice@company.com src_ip=203.0.113.45 result=failed reason=invalid_password attempt=3 Field extraction, applied at search time:
| rex field=_raw "user=(?<user_id>[^\s]+)"
| rex field=_raw "src_ip=(?<source_ip>[^\s]+)"
| rex field=_raw "result=(?<auth_result>[^\s]+)" This regex parsing executes every time you query these fields, not once at ingestion.
The compute cost compounds.
For a single ad-hoc search, parsing overhead is negligible. For dashboards refreshing every 5 minutes and correlation rules running continuously, costs compound dramatically. An authentication failure dashboard counting failed logins per user across 24 hours scans 50 GB of logs daily, runs regex operations across 50 million events, and refreshes 288 times per day. At Splunk Cloud's $0.50–1.50/query pricing, that single dashboard costs about $288/day, or $8,640/month.
Multiply across a typical SOC: 20 dashboards × $8,640 = $172,800/month. 100 correlation rules running continuously adds another $200,000+/month. Total: $370,000+/month in repeated parsing costs at the upper bound. This is the repeated parsing problem at enterprise scale.
Splunk's answer: Data Model Acceleration.
Splunk's answer to repeated parsing is Data Model Acceleration (DMA) — essentially materialized views
for TSIDX summaries. Define a data model specifying field extractions and structure, enable
acceleration (Splunk pre-computes TSIDX summaries in background), and query using
tstats instead of search.
Performance impact documented by Hurricane Labs: unaccelerated search 10.232 seconds, accelerated
tstats query 0.038 seconds — a 270× speedup. Splunk Enterprise Security relies heavily on
accelerated data models for correlation searches; without acceleration, ES correlation rules would
timeout or consume excessive resources.
But DMA has significant limitations. Storage overhead consumes 10–50% of raw data size. CPU overhead for background summarization competes with production workloads. Acceleration gaps appear when summarization jobs timeout or fail. Schema rigidity means changes to a data model require full re-acceleration. Splunk's own documentation warns that "index-time custom field extraction can degrade performance at both index time and search time by enlarging indexes." Translation: pre-extracting fields at ingestion (moving toward schema-on-write) creates its own performance challenges in Splunk's architecture.
Schema-on-write
Pre-structure everything.
Elasticsearch, Microsoft Sentinel, and Google Chronicle take the opposite approach: define schema at ingestion, store data in structured format, query structured fields directly without runtime parsing.
An Elasticsearch index mapping:
{
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"user_id": { "type": "keyword" },
"source_ip": { "type": "ip" },
"auth_result": { "type": "keyword" },
"attempt_count": { "type": "integer" }
}
}
} The same authentication event, structured storage:
{
"timestamp": "2024-01-15T14:23:47Z",
"user_id": "alice@company.com",
"source_ip": "203.0.113.45",
"auth_result": "failed",
"attempt_count": 3
} Field queries access pre-indexed fields directly — no regex parsing at query time. Comparing across platforms on the authentication-failure dashboard query:
| Approach | Query time | Cost / query | Queries / day | Daily cost |
|---|---|---|---|---|
| Splunk (unaccelerated) | 30–90 sec | $1.00–1.50 | 288 | $288–432 |
| Splunk (DMA accelerated) | 1–5 sec | $0.10–0.30 | 288 | $29–86 |
| Elasticsearch | 1–3 sec | $0.05–0.15 | 288 | $14–43 |
Monthly cost projection at 1 TB/day ingestion: Splunk unaccelerated $31,000/month; Splunk with DMA $12,000–18,000/month (acceleration overhead reduces savings); Elasticsearch $8,000–12,000/month. Cost savings: 61–74% versus unaccelerated Splunk, 33–50% versus accelerated Splunk.
The reindexing problem.
Schema-on-write's major limitation: every schema change potentially requires reindexing historical data.
Ingest authentication logs for 6 months with source_ip stored as keyword, then
realize you need IP range queries — which require ip field type, not keyword.
Elasticsearch now needs you to create a new index with corrected mapping, reindex 6 months of data
(potentially terabytes), update all queries and dashboards to reference the new index, then delete the
old. Reindexing 500 GB at 50 MB/sec is 2.8 hours best case; at petabyte scale with cluster overhead, days
to weeks.
Every new log source also requires parser development before ingestion. Unknown formats cannot be ingested "as-is" and explored later — they must be mapped to schema first. This is the operational tax that schema-on-write architectures take on in exchange for the query-performance and cost wins.
Why schema-on-read still matters
The 100+ data source problem.
Enterprise security operations ingest logs from 100–200 different sources. Endpoint vendors (CrowdStrike, SentinelOne, Defender, Carbon Black) each invent their own field names. Network vendors (Palo Alto, Cisco, Fortinet, Check Point) have zero standardization. Cloud providers (AWS CloudTrail, Azure Activity, GCP Audit) have three different schema patterns. SaaS vendors (Okta, Office 365, Salesforce, Workday) each invent their own structure.
Field name variations for "source IP address":
| Vendor | Field name |
|---|---|
| CrowdStrike | RemoteIP |
| SentinelOne | SrcIpAddr |
| Palo Alto | src |
| AWS CloudTrail | sourceIPAddress |
| Azure | caller_ip_address |
| Okta | client.ipAddress |
Schema-on-write approach: map every vendor's field to a standardized schema at ingestion (OCSF, ECS, CIM). Schema-on-read approach: ingest as-is, handle field variations at query time:
| eval source_ip=coalesce(RemoteIP, SrcIpAddr, src, sourceIPAddress, caller_ip_address, 'client.ipAddress') Operational flexibility: schema-on-read allows ingesting new log sources immediately and exploring data before committing to schema design. Schema-on-write requires 2–3 days of parser development per source before ingestion.
Retroactive field extraction during investigations.
Threat hunting scenario: investigating suspected data exfiltration, you hypothesize DNS tunneling is the
method. You need to extract the query_length field from DNS logs to identify unusually long
queries (>100 characters).
Schema-on-read (Splunk):
index=dns
| rex field=_raw "query=(?<dns_query>[^\s]+)"
| eval query_length=len(dns_query)
| where query_length > 100 Result: extract new field retroactively from 90 days of DNS logs, no reindexing required.
Schema-on-write (Elasticsearch): if query_length wasn't in your original index mapping,
you have two options. Runtime field (Elasticsearch 7.11+) calculates the field at query time using
Painless script (performance penalty similar to schema-on-read). Or reindex 90 days of DNS logs with
new field mapping — hours to days of work.
Operational reality: investigations evolve unpredictably. The fields needed emerge from data patterns discovered during analysis, not from predefined schemas. This flexibility is why Splunk remains dominant in threat hunting despite being 3–10× more expensive than schema-on-write alternatives.
CIM as middle ground.
Splunk's Common Information Model provides standardized field names across data sources while
maintaining schema-on-read flexibility. Vendors provide "add-ons" that map their raw formats to CIM
fields at search time, not index time. Searches reference CIM field names
(src_ip, dest_ip, user) regardless of vendor. Underlying raw data
remains unmodified. Vendor-neutral detection rules become portable across SIEMs.
Limitations: field extraction still happens at search time (repeated parsing overhead remains). Not all vendors provide CIM-compliant add-ons. CIM coverage is incomplete (~40 data models, doesn't cover all log types). Elastic Common Schema (ECS) and OCSF provide similar standardization but require schema-on-write normalization at ingestion, not search-time mapping.
The hybrid approach
Raw retention plus normalized projection.
Production security architectures increasingly adopt dual storage: raw data (schema-on-read) plus normalized data (schema-on-write). The pattern:
Security Logs (100+ sources)
↓
Routing Layer (Cribl, Tenzir)
↓
├─→ Raw Storage (S3 + Iceberg, schema-on-read)
│ └─→ Threat Hunting (DuckDB, Trino)
│
└─→ Normalized Storage (OCSF schema-on-write)
└─→ Detection + Dashboards (ClickHouse, Elasticsearch) Raw storage tier: store original events without transformation. Compression: ZSTD (30–50× reduction). Query engines: DuckDB, Trino, Dremio (schema-on-read capable). Cost: $0.023/GB/month (S3 standard) = $690/month for 30 TB. Use case: threat hunting, forensic investigation, retroactive analysis.
Normalized storage tier: OCSF/ECS/CIM-normalized at ingestion. Optimized for query performance (columnar formats, sorted by timestamp). Query engines: ClickHouse, StarRocks, Elasticsearch. Cost: $3,000–8,000/month depending on platform. Use case: real-time detection, dashboards, compliance reporting.
Cost-benefit analysis.
1 TB/day ingestion, 90-day retention:
| Component | Storage | Monthly cost | Use case |
|---|---|---|---|
| Raw (S3 + Iceberg) | 90 TB after 30× compression | $2,070 | Hunting |
| Normalized (ClickHouse) | 15 TB hot (7d) + 75 TB warm/cold | $5,500 | Detection |
| Total hybrid | 105 TB | $7,570/month | Both |
| Splunk equivalent | 90 TB | $31,000/month | Both |
Cost savings: 76% ($23,430/month). Capability comparison: hybrid matches Splunk on real-time detection (normalized tier), threat hunting (raw tier), retroactive field extraction (raw tier), and beats Splunk on dashboard performance (no DMA gaps) while delivering $7.6K versus $31K monthly cost.
Production validation — Fortune 500 financial institution.
A 2 PB/day OCSF-normalized security data lake, 3+ years production. Raw tier: Parquet files on S3, cataloged in Unity Catalog, queried via Trino. Normalized tier: ClickHouse for real-time detection, Databricks for analytics. Routing: Cribl Stream with OCSF normalization pipelines.
Results: $2.1M/year cost reduction versus Splunk (66%). Sub-second detection latency for 800 OCSF-based correlation rules. Threat hunters query 60 days of raw data via DuckDB notebooks. New log sources added without disrupting detection rules (OCSF abstraction holds the contract).
Migration approach: 6-month parallel operation (Splunk + lakehouse), gradual workload migration per business unit, zero forced cutover dates. The parallel-operation pattern is what makes the migration tractable; cutover-style migrations are where most failures happen.
Iceberg V3 Variant — the third option
Schema-on-read semantics inside a schema-on-write format.
This essay frames schema-on-read vs schema-on-write as a binary architectural choice and resolves it
with a hybrid pattern. Iceberg V3 introduces a third option that partially dissolves the binary: the
Variant type (semi-structured/nested JSON, ratified in Parquet October 2025) lets you have
schema-on-read semantics inside a schema-on-write storage format. Concretely: you can store a
CloudTrail event as (eventTime TIMESTAMP, eventName STRING, raw_event VARIANT) in an
Iceberg table, query the structured fields with predicate pushdown, AND retain the full nested JSON for
retroactive field extraction during investigations. See the
Iceberg V3/V4 recalibration essay for the longer take.
Variant doesn't eliminate the "$2.7M remapping" problem this essay describes — it doesn't eliminate the need to maintain OCSF-normalized projections for cross-vendor query consistency. But it does substantially change the cost calculation. The raw-retention layer no longer requires a separate Splunk-style schema-on-read system, and the normalized projection no longer has to be exhaustive — you can OCSF-project the top-50 fields and leave the long tail in the Variant column for hunting-tier access.
Adoption caveat: V3 Variant engine support is still rolling out across Spark, Trino, DuckDB, and
Snowflake through 2026. The hybrid architecture this essay recommends is still the right answer if
your engine doesn't support variant_get() yet.
Cloud-native schema-on-write
Sentinel and Chronicle as proof points.
Microsoft Sentinel — ingestion-time normalization.
Microsoft Sentinel performs schema-on-write normalization at ingestion using Data Collection Rules and ASIM (Advanced Security Information Model). Logs ingested via Azure Monitor Agent or API; Data Collection Rules apply transformations (field mapping, filtering, enrichment); data stored in Log Analytics workspace (KQL-queryable); ASIM provides normalized schema layer.
Cost advantage: Azure-native logs (Azure AD, Defender, Office 365) ingest free for E5 licensed users. Only third-party logs incur ingestion costs ($2.30/GB). For 200 GB/day with 80% Azure-native and 20% third-party: Azure-native (160 GB/day) $0/month; third-party (40 GB/day) $2,760/month. Splunk equivalent at 200 GB/day × $150/GB/year = $30,000/month. Cost savings: 91% for Azure-heavy environments.
Limitations: vendor lock-in (KQL not portable, data export expensive). 90-day retention ceiling for hot tier (Archive tier requires extra queries). Cost explosion at scale — 500 GB/day third-party = $414K/year.
Google Chronicle — BigQuery-powered security.
Google Chronicle (SecOps) stores security data in BigQuery with Universal Data Model (UDM) normalization at ingestion. Chronicle connectors ingest from 200+ sources; UDM normalization applied at ingestion (similar to OCSF); data stored in BigQuery columnar format; SQL queries via BigQuery engine (distributed, 1,000+ workers).
Cost advantage: storage at $0.020/GB/month — S3-equivalent, versus Splunk $12.50/GB/month for indexed storage. For 500 GB/day with 5-year retention: storage 912 TB × $0.020 = $18,240/month; query compute ~$5,000/month estimated. Total: ~$23,000/month. Splunk equivalent for 912 TB indexed: $11.4M/month — not realistic, hence Splunk archives to reduce cost.
Why Chronicle validates lakehouse architecture: Google wouldn't bet SecOps on BigQuery if lakehouse patterns didn't work for security at scale. The fact that Chronicle is a lakehouse — separation of storage/compute, columnar format, SQL queries, schema-on-write normalization — proves the architecture is production-viable.
Decision framework
When each approach wins.
Choose schema-on-read when:
- 100+ diverse data sources with inconsistent field naming
- Exploratory threat hunting is a core operational requirement
- Retroactive field extraction during investigations is common
- New log sources appear frequently (M&A, vendor changes)
- Small-to-medium scale (<500 GB/day where costs are manageable)
- Splunk expertise already exists and transition costs are prohibitive
Cost tolerance: accept 3–10× higher costs for operational flexibility.
Choose schema-on-write when:
- Known detection patterns dominate (dashboards, compliance, scheduled queries)
- Schema stability exists (mature security stack, infrequent log source changes)
- Cost optimization is the priority (budget-constrained, high volumes)
- Cloud-native environment (Azure/GCP with free ingestion for native logs)
- Data engineering expertise available (to build normalization pipelines)
Cost benefit: 60–75% savings versus schema-on-read at scale.
Choose hybrid (raw + normalized) when:
- Petabyte-scale volumes make pure schema-on-read cost-prohibitive
- Both hunting and detection are critical operational requirements
- OCSF/ECS/ASIM adoption provides a stable normalization target
- Data engineering team can build and maintain dual storage
- 1–2 year timeline acceptable for migration with parallel operation
Sweet spot: 1 TB/day to 10 TB/day organizations with mature security operations.
Practical recommendations
For Splunk-resident teams and greenfield builders.
For organizations currently on Splunk.
Don't rush migration. Splunk's schema-on-read flexibility isn't easily replaced. The 6-month parallel operation pattern seen in Fortune 500 deployments exists for good reasons: detection rule migration (800 SPL rules → SQL requires validation, not blind conversion); analyst training (SQL + data lakehouse concepts require 3–6 months of upskilling); schema normalization (OCSF mapping for 40+ sources is 2–3 days per source); workflow adjustments (hunting patterns differ between schema-on-read and normalized lakehouses).
Pilot approach: start with 2–3 high-volume, low-complexity sources (VPC Flow, DNS, CloudTrail). Build OCSF normalization pipeline with validation against Splunk results. Run parallel queries in both systems for 90 days, compare detection coverage. Expand to additional sources only after validation success.
For organizations building new architecture.
Start with hybrid from day one. Raw tier: S3 + Iceberg catalog + DuckDB/Trino query engines. Normalized tier: OCSF schema-on-write in ClickHouse/StarRocks. Routing layer: Cribl or Tenzir with dual-write to both tiers.
Storage ratio: 90% of data volume in raw tier (compressed), 10% in normalized hot tier (7–30 days). Query routing: known patterns (dashboards, detection) → normalized tier; exploratory hunting → raw tier; compliance/forensics → raw tier (legal requires original unmodified logs).
Cost: $7,000–15,000/month for 1 TB/day (versus $31,000 Splunk).
For OCSF normalization specifically.
LLM-assisted mapping reduces field-mapping time from 7 hours to 75 minutes per source (6× efficiency). Provide the LLM with vendor schema plus OCSF spec; LLM generates mapping in ~45 seconds (92–95% accuracy); human reviews low-confidence fields (~15 min); test mapping against sample data (~10 min).
40 sources: 280 hours manual → 50 hours LLM-assisted = $41,400 labor savings at $180/hour data engineer rate.
Avoid over-mapping: map only fields actually used in detection rules and dashboards (typically 15–30 fields per source), not all 100+ available fields. The over-mapping trap converts a reasonable schema-on-write architecture into a schema-on-write-everything architecture that loses most of the cost benefit and adds operational drag.
There is no universal answer
Both approaches solve different problems.
Schema-on-read optimizes for operational flexibility at the cost of query performance and expense. For threat hunting workloads where investigation paths are unpredictable, this trade-off is justified.
Schema-on-write optimizes for query performance and cost efficiency at the cost of schema rigidity. For known detection patterns and compliance reporting, this trade-off is optimal.
Hybrid architectures provide the best of both worlds for organizations with sufficient data engineering expertise and scale (1+ TB/day) to justify the operational complexity.
The $2.7M question isn't "which approach is better?" but rather "which problems am I solving, and what costs am I willing to accept?" For petabyte-scale security data infrastructure prioritizing manageability over extreme performance, dual storage (raw + normalized) is the emerging best practice; OCSF/ECS/ASIM normalization is a strategic hedge against vendor lock-in; selective materialization (dashboards, compliance) beats universal acceleration; 6-month parallel operation during migration is what makes the change tractable; and schema-on-read preservation matters for threat hunting even in schema-on-write architectures.
The platforms advancing state-of-the-art — Chronicle's BigQuery lakehouse, Sentinel's ASIM normalization, OCSF's vendor-neutral schema, Iceberg V3's Variant type — all point toward hybrid approaches rather than religious adherence to one paradigm. Build for both. Optimize where it matters. Preserve flexibility where investigation demands it.
The $2.7M question is not abstract.
The Splunk-to-MOAR migration assessment quantifies the trade-off against your specific workload — your ingest volume, your detection patterns, your retention regime — and produces a TCO comparison plus phased migration plan you can execute or shelve. Two to three weeks. Fixed price.