NoSQL Expert Patterns (Cassandra, ScyllaDB & DynamoDB)
Overview
This skill provides professional mental models and design patterns for distributed wide-column and key-value stores (Apache Cassandra, ScyllaDB, and Amazon DynamoDB).
Unlike SQL (where you model data entities), or document stores (like MongoDB), these distributed systems require you to model your queries first. You cannot "add a query later" without migration or creating a new table/index.
The Golden Rule: In SQL, you design the data model to answer any query. In NoSQL, you design the data model to answer specific queries efficiently.
The Mental Shift: SQL vs. Distributed NoSQL
| Feature |
SQL (Relational) |
Distributed NoSQL (Cassandra/DynamoDB) |
| Data modeling |
Model Entities + Relationships |
Model Queries (Access Patterns) |
| Joins |
CPU-intensive, at read time |
Pre-computed (Denormalized) at write time |
| Storage cost |
Expensive (minimize duplication) |
Cheap (duplicate data for read speed) |
| Consistency |
ACID (Strong) |
BASE (Eventual) / Tunable |
| Scalability |
Vertical (Bigger machine) |
Horizontal (More nodes/shards) |
When to Use
- Designing for Scale: Moving beyond simple single-node databases to distributed clusters.
- Technology Selection: Evaluating or using Cassandra, ScyllaDB, or DynamoDB.
- Schema Modeling: Designing tables, partition keys, sort keys, or single-table layouts.
- Performance Tuning: Troubleshooting "hot partitions", high latency, or uneven traffic in existing NoSQL systems.
- Microservices: Implementing "database-per-service" patterns where highly optimized reads are required.
Prerequisites
- Target database identified (Cassandra/ScyllaDB or DynamoDB).
- A complete list of required access patterns (queries) before table design.
- Understanding of expected read/write volume and cardinality of candidate partition keys.
- If running locally on Windows (PowerShell), ensure
cqlsh or AWS CLI v2 is installed and configured with placeholder credentials (YOUR_KEY).
Procedure
1. Query-First Modeling (Access Patterns)
You typically cannot "add a query later" without migration or creating a new table/index.
- List all Entities (User, Order, Product).
- List all Access Patterns ("Get User by Email", "Get Orders by User sorted by Date").
- Design Table(s) specifically to serve those patterns with a single lookup.
- Validate that every access pattern maps to exactly one table or index.
2. Choose the Partition Key (PK)
Data is distributed across physical nodes based on the Partition Key (PK).
- Goal: Even distribution of data and traffic.
- Anti-Pattern: Using a low-cardinality PK (e.g.,
status="active" or gender="m") creates Hot Partitions, limiting throughput to a single node's capacity.
- Best Practice: Use high-cardinality keys (User IDs, Device IDs, Composite Keys).
- Split Partition Risk: For any single partition (e.g., a single user's orders), will it grow indefinitely? If a partition may exceed 10GB, shard it (e.g.,
USER#123#2024-01).
3. Choose Clustering / Sort Keys
Within a partition, data is sorted on disk by the Clustering Key (Cassandra) or Sort Key (DynamoDB).
- Enables efficient Range Queries (e.g.,
WHERE user_id=X AND date > Y).
- Pre-sorts data for specific retrieval requirements.
4. Single-Table Design (Adjacency Lists)
Primary use: DynamoDB (but concepts apply elsewhere)
Storing multiple entity types in one table to enable pre-joined reads.
| PK (Partition) |
SK (Sort) |
Data Fields... |
USER#123 |
PROFILE |
{ name: "Ian", email: "..." } |
USER#123 |
ORDER#998 |
{ total: 50.00, status: "shipped" } |
USER#123 |
ORDER#999 |
{ total: 12.00, status: "pending" } |
- Query:
PK="USER#123"
- Result: Fetches User Profile AND all Orders in one network request.
5. Denormalization & Duplication
Store the same data in multiple tables to serve different query patterns.
- Table A:
users_by_id (PK: uuid)
- Table B:
users_by_email (PK: email)
Trade-off: You must manage data consistency across tables (often using eventual consistency or batch writes).
6. Apache Cassandra / ScyllaDB Specifics
- Primary Key Structure:
((Partition Key), Clustering Columns)
- No Joins, No Aggregates: Do not try to
JOIN or GROUP BY. Pre-calculate aggregates in a separate counter table.
- Avoid
ALLOW FILTERING: If you see this in production, your data model is wrong. It implies a full cluster scan.
- Writes are Cheap: Inserts and Updates are just appends to the LSM tree. Don't worry about write volume as much as read efficiency.
- Tombstones: Deletes are expensive markers. Avoid high-velocity delete patterns (like queues) in standard tables.
7. AWS DynamoDB Specifics
- GSI (Global Secondary Index): Use GSIs to create alternative views of your data (e.g., "Search Orders by Date" instead of by User). GSIs are eventually consistent.
- LSI (Local Secondary Index): Sorts data differently within the same partition. Must be created at table creation time.
- WCU / RCU: Understand capacity modes. Single-table design helps optimize consumed capacity units.
- TTL: Use Time-To-Live attributes to automatically expire old data (free delete) without creating tombstones.
Examples
Cassandra: Users by Email Lookup
CREATE TABLE users_by_email (
email text,
user_id uuid,
name text,
created_at timestamp,
PRIMARY KEY (email)
);
Query: SELECT * FROM users_by_email WHERE email = 'ian@example.com';
DynamoDB: Single-Table User + Orders
PK: USER#123 SK: PROFILE -> { name, email }
PK: USER#123 SK: ORDER#2024-001 -> { total, status }
PK: USER#123 SK: ORDER#2024-002 -> { total, status }
Query: Query PK=USER#123 returns the profile and all orders in one request.
Pitfalls
- ❌ Scatter-Gather: Querying all partitions to find one item (Scan).
- ❌ Hot Keys: Putting all "Monday" data into one partition.
- ❌ Relational Modeling: Creating
Author and Book tables and trying to join them in code. Instead, embed Book summaries in Author, or duplicate Author info in Books.
- ❌ Low-Cardinality PK:
status, gender, or country as a partition key creates hot partitions.
- ❌ Unbounded Partitions: A single user's orders growing forever without sharding.
- ❌
ALLOW FILTERING in Cassandra: Indicates a broken data model requiring a full cluster scan.
- ❌ High-Velocity Deletes: Creates tombstones that degrade read performance in Cassandra.
- ❌ Forgetting GSI Consistency: GSIs are eventually consistent; do not use them for strong-consistency requirements.
Verification
Before finalizing your NoSQL schema, run through this checklist:
Checkable Commands
Cassandra/ScyllaDB (Windows PowerShell, cqlsh on PATH):
cqlsh localhost 9042 -e "DESCRIBE TABLE keyspace.users_by_email;"
cqlsh localhost 9042 -e "SELECT COUNT(*) FROM keyspace.users_by_email WHERE email='ian@example.com';"
DynamoDB (AWS CLI v2, placeholder credentials):
aws dynamodb describe-table --table-name UsersOrders --endpoint-url http://localhost:8000
aws dynamodb query --table-name UsersOrders --key-condition-expression "PK = :pk" --expression-attribute-values '{":pk":{"S":"USER#123"}}' --endpoint-url http://localhost:8000
Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
1---2name: nosql-expert3description: Models Cassandra, ScyllaDB, and DynamoDB access patterns as tables: high-cardinality partition keys, clustering or sort keys, single-table adjacency lists, GSIs, and duplicated lookup tables. Trigger on hot partitions, ALLOW FILTERING, or DynamoDB single-table design. Never apply MongoDB document schemas or SQL join thinking to these stores.4---5
6# NoSQL Expert Patterns (Cassandra, ScyllaDB & DynamoDB)
7
8## Overview
9
10This skill provides professional mental models and design patterns for **distributed wide-column and key-value stores** (Apache Cassandra, ScyllaDB, and Amazon DynamoDB).
11
12Unlike SQL (where you model data entities), or document stores (like MongoDB), these distributed systems require you to **model your queries first**. You cannot "add a query later" without migration or creating a new table/index.
13
14> **The Golden Rule:** In SQL, you design the data model to answer *any* query. In NoSQL, you design the data model to answer *specific* queries efficiently.
15
16### The Mental Shift: SQL vs. Distributed NoSQL
17
18| Feature | SQL (Relational) | Distributed NoSQL (Cassandra/DynamoDB) |
19| :--- | :--- | :--- |
20| **Data modeling** | Model Entities + Relationships | Model **Queries** (Access Patterns) |
21| **Joins** | CPU-intensive, at read time | **Pre-computed** (Denormalized) at write time |
22| **Storage cost** | Expensive (minimize duplication) | Cheap (duplicate data for read speed) |
23| **Consistency** | ACID (Strong) | **BASE (Eventual)** / Tunable |
24| **Scalability** | Vertical (Bigger machine) | **Horizontal** (More nodes/shards) |
25
26## When to Use
27
28- **Designing for Scale**: Moving beyond simple single-node databases to distributed clusters.
29- **Technology Selection**: Evaluating or using **Cassandra**, **ScyllaDB**, or **DynamoDB**.
30- **Schema Modeling**: Designing tables, partition keys, sort keys, or single-table layouts.
31- **Performance Tuning**: Troubleshooting "hot partitions", high latency, or uneven traffic in existing NoSQL systems.
32- **Microservices**: Implementing "database-per-service" patterns where highly optimized reads are required.
33
34## Prerequisites
35
36- Target database identified (Cassandra/ScyllaDB or DynamoDB).
37- A complete list of required **access patterns** (queries) before table design.
38- Understanding of expected read/write volume and cardinality of candidate partition keys.
39- If running locally on Windows (PowerShell), ensure `cqlsh` or AWS CLI v2 is installed and configured with placeholder credentials (`YOUR_KEY`).
40
41## Procedure
42
43### 1. Query-First Modeling (Access Patterns)
44
45You typically cannot "add a query later" without migration or creating a new table/index.
46
471. **List all Entities** (User, Order, Product).
482. **List all Access Patterns** ("Get User by Email", "Get Orders by User sorted by Date").
493. **Design Table(s)** specifically to serve those patterns with a single lookup.
504. **Validate** that every access pattern maps to exactly one table or index.
51
52### 2. Choose the Partition Key (PK)
53
54Data is distributed across physical nodes based on the **Partition Key (PK)**.
55
56- **Goal:** Even distribution of data and traffic.
57- **Anti-Pattern:** Using a low-cardinality PK (e.g., `status="active"` or `gender="m"`) creates **Hot Partitions**, limiting throughput to a single node's capacity.
58- **Best Practice:** Use high-cardinality keys (User IDs, Device IDs, Composite Keys).
59- **Split Partition Risk:** For any single partition (e.g., a single user's orders), will it grow indefinitely? If a partition may exceed **10GB**, shard it (e.g., `USER#123#2024-01`).
60
61### 3. Choose Clustering / Sort Keys
62
63Within a partition, data is sorted on disk by the **Clustering Key (Cassandra)** or **Sort Key (DynamoDB)**.
64
65- Enables efficient **Range Queries** (e.g., `WHERE user_id=X AND date > Y`).
66- Pre-sorts data for specific retrieval requirements.
67
68### 4. Single-Table Design (Adjacency Lists)
69
70*Primary use: DynamoDB (but concepts apply elsewhere)*
71
72Storing multiple entity types in one table to enable pre-joined reads.
73
74| PK (Partition) | SK (Sort) | Data Fields... |
75| :--- | :--- | :--- |
76| `USER#123` | `PROFILE` | `{ name: "Ian", email: "..." }` |
77| `USER#123` | `ORDER#998` | `{ total: 50.00, status: "shipped" }` |
78| `USER#123` | `ORDER#999` | `{ total: 12.00, status: "pending" }` |
79
80- **Query:** `PK="USER#123"`
81- **Result:** Fetches User Profile AND all Orders in **one network request**.
82
83### 5. Denormalization & Duplication
84
85Store the same data in multiple tables to serve different query patterns.
86
87- **Table A:** `users_by_id` (PK: uuid)
88- **Table B:** `users_by_email` (PK: email)
89
90*Trade-off: You must manage data consistency across tables (often using eventual consistency or batch writes).*
91
92### 6. Apache Cassandra / ScyllaDB Specifics
93
94- **Primary Key Structure:** `((Partition Key), Clustering Columns)`
95- **No Joins, No Aggregates:** Do not try to `JOIN` or `GROUP BY`. Pre-calculate aggregates in a separate counter table.
96- **Avoid `ALLOW FILTERING`:** If you see this in production, your data model is wrong. It implies a full cluster scan.
97- **Writes are Cheap:** Inserts and Updates are just appends to the LSM tree. Don't worry about write volume as much as read efficiency.
98- **Tombstones:** Deletes are expensive markers. Avoid high-velocity delete patterns (like queues) in standard tables.
99
100### 7. AWS DynamoDB Specifics
101
102- **GSI (Global Secondary Index):** Use GSIs to create alternative views of your data (e.g., "Search Orders by Date" instead of by User). GSIs are eventually consistent.
103- **LSI (Local Secondary Index):** Sorts data differently *within* the same partition. Must be created at table creation time.
104- **WCU / RCU:** Understand capacity modes. Single-table design helps optimize consumed capacity units.
105- **TTL:** Use Time-To-Live attributes to automatically expire old data (free delete) without creating tombstones.
106
107## Examples
108
109### Cassandra: Users by Email Lookup
110
111```sql
112CREATE TABLE users_by_email (
113 email text,
114 user_id uuid,
115 name text,
116 created_at timestamp,
117 PRIMARY KEY (email)
118);
119```
120
121Query: `SELECT * FROM users_by_email WHERE email = 'ian@example.com';`
122
123### DynamoDB: Single-Table User + Orders
124
125```text
126PK: USER#123 SK: PROFILE -> { name, email }
127PK: USER#123 SK: ORDER#2024-001 -> { total, status }
128PK: USER#123 SK: ORDER#2024-002 -> { total, status }
129```
130
131Query: `Query PK=USER#123` returns the profile and all orders in one request.
132
133## Pitfalls
134
135- ❌ **Scatter-Gather:** Querying *all* partitions to find one item (Scan).
136- ❌ **Hot Keys:** Putting all "Monday" data into one partition.
137- ❌ **Relational Modeling:** Creating `Author` and `Book` tables and trying to join them in code. Instead, embed Book summaries in Author, or duplicate Author info in Books.
138- ❌ **Low-Cardinality PK:** `status`, `gender`, or `country` as a partition key creates hot partitions.
139- ❌ **Unbounded Partitions:** A single user's orders growing forever without sharding.
140- ❌ **`ALLOW FILTERING` in Cassandra:** Indicates a broken data model requiring a full cluster scan.
141- ❌ **High-Velocity Deletes:** Creates tombstones that degrade read performance in Cassandra.
142- ❌ **Forgetting GSI Consistency:** GSIs are eventually consistent; do not use them for strong-consistency requirements.
143
144## Verification
145
146Before finalizing your NoSQL schema, run through this checklist:
147
148- [ ] **Access Pattern Coverage:** Does every query pattern map to a specific table or index?
149- [ ] **Cardinality Check:** Does the Partition Key have enough unique values to spread traffic evenly?
150- [ ] **Split Partition Risk:** For any single partition (e.g., a single user's orders), will it grow indefinitely? (If > 10GB, shard the partition, e.g., `USER#123#2024-01`).
151- [ ] **Consistency Requirement:** Can the application tolerate eventual consistency for this read pattern?
152- [ ] **No Scans:** Are all production queries `SELECT`/`Query` by key, not `Scan`?
153- [ ] **No `ALLOW FILTERING`:** Confirm no Cassandra queries use `ALLOW FILTERING`.
154
155### Checkable Commands
156
157Cassandra/ScyllaDB (Windows PowerShell, `cqlsh` on PATH):
158
159```powershell
160cqlsh localhost 9042 -e "DESCRIBE TABLE keyspace.users_by_email;"
161cqlsh localhost 9042 -e "SELECT COUNT(*) FROM keyspace.users_by_email WHERE email='ian@example.com';"
162```
163
164DynamoDB (AWS CLI v2, placeholder credentials):
165
166```powershell
167aws dynamodb describe-table --table-name UsersOrders --endpoint-url http://localhost:8000
168aws dynamodb query --table-name UsersOrders --key-condition-expression "PK = :pk" --expression-attribute-values '{":pk":{"S":"USER#123"}}' --endpoint-url http://localhost:8000
169```
170
171## Limitations
172
173- Use this skill only when the task clearly matches the scope described above.
174- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
175- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.