Implementing Column-Family Stores

1. Designing Column Families

ConceptDetail
KeyspaceTop-level namespace (like DB)
Table (CF)Collection of partitions
Partition keyDetermines node placement
Clustering columnsSort within partition
ColumnsWide-row; varying per partition

Example: Cassandra Table

CREATE TABLE events_by_user (
  user_id   UUID,
  event_ts  TIMESTAMP,
  event_id  TIMEUUID,
  payload   TEXT,
  PRIMARY KEY ((user_id), event_ts, event_id)
) WITH CLUSTERING ORDER BY (event_ts DESC, event_id DESC);

2. Modeling Wide Rows

PatternDetail
Time-series per entityPartition by entity_id, cluster by time
Bucket partition(user_id, yyyymm) — limit partition size
Partition size limitTarget < 100 MB / 100k rows
Avoid unbounded growthReshard by time

3. Designing Partition Keys

GoalDetail
Even distributionHigh cardinality keys
Query-friendlySingle-partition reads where possible
Composite keys(tenant_id, day) for bounded shards
Avoid hot partitionsNo single key catching all writes

4. Implementing Clustering Columns

UseDetail
Sort within partitionASC / DESC defined in DDL
Range scansEfficient — sequential on disk
Order mattersEquality only on prefix; range on last column

5. Designing for Time-Series Data

TipDetail
Bucket by day/hourPrevent unbounded partitions
TimeWindowCompactionStrategyTWCS — best for TS workloads
TTL on rowsAuto-expire old data
Clustering by ts DESCCheap "latest N" queries

6. Modeling for Write-Heavy Workloads

PropertyDetail
LSM treeAppend-friendly architecture
No read-before-writeUPSERT semantics by default
Counter tablesAtomic increment column type
Batch with careLOGGED batch costly; use UNLOGGED for same partition

7. Implementing Secondary Indexes

TypeDetail
Local secondary (2i)Per-node — scatter-gather; only with partition key
SASIDeprecated
SAI (newer)Better global secondary indexing
Materialized viewsServer-maintained denormalized table
Best practiceModel query-first; create denormalized table per access pattern

8. Querying with CQL

Example: CQL Queries

SELECT * FROM events_by_user
WHERE user_id = ? AND event_ts >= ? AND event_ts < ?
LIMIT 100;

INSERT INTO events_by_user (user_id, event_ts, event_id, payload)
VALUES (?, ?, now(), ?) USING TTL 2592000;  -- 30 days
Warning: ALLOW FILTERING is a footgun — forces full-table scan. Model query-first instead.

9. Managing Consistency Levels

LevelMeaning
ONEOne replica responds
QUORUMMajority (RF/2 + 1)
LOCAL_QUORUMMajority in local DC (cross-DC tolerant)
ALLAll replicas (lowest availability)
EACH_QUORUMQuorum in each DC
RuleR + W > RF for strong consistency

10. Optimizing Column-Family Queries

TipDetail
Always provide partition keyAvoid multi-partition reads
Limit clustering rangeTargeted slice
Use prepared statementsParser cache + safety
Right compaction strategySTCS, LCS, TWCS per workload
Monitor tombstonesExcessive deletes hurt reads