Indexes in Cassandra
Indexes in Cassandra allow you to quickly search data using non-primary-key columns. They act like lookup shortcuts — helping queries run faster when filtering on specific fields.
📖 The Story: Lisa's Slow Query Crisis
Lisa built an e-commerce app with 10 million products. Users want to search by brand, category, and price. She modeled the table with product_id as the partition key...
❌ Attempt 1: Query Without Index (DISASTER!)
Problems:
- 💥 Query fails! Can't filter by non-primary key columns
- 🐌 Even with ALLOW FILTERING, scans ALL 10 million rows!
- ⏱️ Query takes 45 seconds (timeout!)
- 😡 Users abandon the site - sales plummet!
⚠️ Attempt 2: ALLOW FILTERING (Hacky & Slow!)
Problems:
- 🔥 Full table scan on 10 million rows!
- ⏱️ Takes 30+ seconds per query
- 💸 Wastes CPU, memory, and disk I/O
- 📉 Can't scale - site crashes under load
✅ The RIGHT Way: Secondary Index!
Benefits:
- ✅ Fast queries: 50ms vs 30 seconds!
- ✅ No full table scan: Only reads relevant partitions
- ✅ Users are happy: Instant search results!
- ✅ Scalable: Works even with 100M products
- ✅ Easy to create: One command, done!
Lisa's site is now blazing fast! Sales are up 300%! 🎉
📑 What are Indexes in Cassandra?
Indexes allow you to query by non-primary key columns efficiently without full table scans.
Simple Definition
Secondary Index: A data structure that allows fast lookups on non-primary key columns.
Think of an Index as:
- 📚 Book Index: Jump to specific pages without reading everything
- 🗂️ Filing System: Find documents by category, not just ID
- 🔍 Search Engine: Quickly locate items by any attribute
- 🗺️ Map Legend: Find locations by name, not coordinates
Why Do We Need Indexes?
Without Index
- Can't Query: WHERE on non-PK columns fails
- ALLOW FILTERING: Scans entire table (slow!)
- Full Table Scan: Reads ALL rows every query
- Poor Performance: Seconds or minutes per query
- Not Scalable: Gets worse as data grows
With Index
- Fast Queries: Milliseconds instead of seconds
- Targeted Reads: Only scans matching rows
- No Filtering: Index does the work for you
- Flexible Queries: Search by any indexed column
- Better UX: Users get instant results
Types of Indexes in Cassandra
1️⃣ Secondary Index (Regular Index)
Most common type - indexes a single column for equality queries.
2️⃣ SASI (SSTable Attached Secondary Index)
Advanced index supporting range queries, LIKE, and case-insensitive searches.
3️⃣ Collection Index
Index on collection types (LIST, SET, MAP) to query elements.
🔨 Creating and Using Indexes
Master the complete index lifecycle: CREATE, USE, DROP.
Creating a Secondary Index
Important: One Column Per Index!
Cassandra doesn't support composite indexes! Each index covers only ONE column.
Querying with Indexes
Dropping an Index
Collection Indexes
⚙️ How Indexes Work Internally
Understanding the internals helps you use indexes wisely!
Index Internals
- Index Table: Cassandra creates a hidden table:
indexed_column → partition_key - Local to Each Node: Each node maintains indexes for its own data
- No Global Index: Query coordinator must contact ALL nodes!
- Automatic Updates: Index updates when you INSERT/UPDATE/DELETE
- Write Overhead: Every write updates both table AND index
🎯 When to Use (and NOT Use) Indexes
Indexes aren't always the answer! Choose wisely.
Good Use Cases
- High Cardinality: Many unique values (email, username)
- Selective Queries: Filter returns small % of rows
- Read-Heavy: More reads than writes
- Equality Searches: WHERE column = value
- Collection CONTAINS: Search within SET/LIST/MAP
Bad Use Cases
- Low Cardinality: Few unique values (gender: M/F)
- Non-Selective: Returns most rows (active: true)
- Write-Heavy: High INSERT/UPDATE volume
- Range Queries: WHERE price > 100 (use SASI)
- Counter Columns: Can't index counters!
Better Alternatives
- Denormalize: Create users_by_email table
- Materialized Views: Auto-maintained tables
- Application-Level: Cache or external search (Elasticsearch)
- Better Modeling: Make column part of primary key
- SASI Index: For range queries and LIKE
Cardinality Examples
✅ HIGH Cardinality (Good for Indexes)
- email: millions of unique values
- username: every user is different
- product_sku: each product unique
- transaction_id: every transaction different
❌ LOW Cardinality (Bad for Indexes)
- gender: only 2-3 values (M/F/Other)
- active: only 2 values (true/false)
- status: 4-5 values (pending/approved/rejected)
- country: ~200 values (might work for small tables)
🚀 SASI Indexes: Advanced Indexing
SASI (SSTable Attached Secondary Index) supports range queries, LIKE searches, and more!
What is SASI?
SASI is an advanced indexing mechanism that overcomes limitations of regular secondary indexes.
SASI Advantages:
- ✅ Range Queries: WHERE price > 100 AND price < 500
- ✅ LIKE Searches: WHERE name LIKE '%phone%'
- ✅ Case-Insensitive: Search regardless of case
- ✅ Prefix/Suffix: name LIKE 'iphone%' or '%.com'
- ✅ Better Performance: Lower memory footprint
Creating SASI Indexes
SASI Query Examples
SASI Modes
- PREFIX: LIKE 'abc%' - starts with
- CONTAINS: LIKE '%abc%' - anywhere
- SPARSE: Numeric ranges, high cardinality
SASI Analyzers
- NonTokenizingAnalyzer: Exact matches, IDs
- StandardAnalyzer: Text search, tokenization
- DelimiterAnalyzer: Custom delimiters
🚀 SASI Indexes: Advanced Indexing
SASI (SSTable Attached Secondary Index) supports range queries, LIKE searches, and more!
What is SASI?
SASI is an advanced indexing mechanism that overcomes limitations of regular secondary indexes.
SASI Advantages:
- ✅ Range Queries: WHERE price > 100 AND price < 500
- ✅ LIKE Searches: WHERE name LIKE '%phone%'
- ✅ Case-Insensitive: Search regardless of case
- ✅ Prefix/Suffix: name LIKE 'iphone%' or '%.com'
- ✅ Better Performance: Lower memory footprint
Creating SASI Indexes
SASI Query Examples
SASI Modes
- PREFIX: LIKE 'abc%' - starts with
- CONTAINS: LIKE '%abc%' - anywhere
- SPARSE: Numeric ranges, high cardinality
SASI Analyzers
- NonTokenizingAnalyzer: Exact matches, IDs
- StandardAnalyzer: Text search, tokenization
- DelimiterAnalyzer: Custom delimiters
🖥️ Interactive Index Console
Practice index commands in our safe simulator!
Try the examples or create your own index...
Available Examples:
• Example 1: Create regular index
• Example 2: SASI index with CONTAINS
• Example 3: Collection index
⭐ Index Best Practices & Common Mistakes
Production-proven strategies and pitfalls to avoid!
DO's
- High Cardinality: Index columns with many unique values
- Name Indexes: Use descriptive names (idx_email)
- Combine with PK: WHERE pk = X AND indexed_col = Y
- Monitor Performance: Track index usage and query times
- Use SASI for Ranges: Better than regular index
- Test Before Production: Measure impact on writes
- Limit Indexes: 3-5 per table maximum
DON'Ts
- Don't Index Low Cardinality: gender, boolean, status
- Don't Over-Index: Every index slows writes!
- Don't Index Write-Heavy: High INSERT/UPDATE tables
- Don't Use for Ranges: Regular index (use SASI instead)
- Don't Forget ALLOW FILTERING: Multi-column queries need it
- Don't Index Large Text: Use external search (Elasticsearch)
- Don't Index Counters: Not supported!
Pro Tips
- Check Query Plans: TRACING ON to see index usage
- Rebuild Indexes: nodetool rebuild_index after major writes
- Denormalize Instead: Often faster than indexes
- Use Materialized Views: Auto-maintained denormalization
- External Search: Elasticsearch for complex text search
- Monitor Write Latency: Indexes add 10-30% overhead
- Drop Unused Indexes: Free up resources
⚠️ Common Mistake: Indexing Low Cardinality Column
The Problem: Developer creates index on 'gender' column with only 3 values (M/F/Other)...
Why It's Bad:
- 🔥 Query still returns millions of rows (not selective)
- ⏱️ Must scan ~50% of table anyway
- 💸 Index takes up disk space for no benefit
- 🐌 Slows down every INSERT/UPDATE/DELETE
The Fix:
Index Performance Impact
Write Overhead:
- Each index adds 10-30% write latency
- 3 indexes = 30-90% slower writes!
- Index must be updated on every INSERT/UPDATE/DELETE
Storage Overhead:
- Index size ≈ 10-20% of table size
- Stored on every node (not replicated separately)
Query Performance:
- ✅ Selective queries (< 10% rows): 100x faster
- ⚠️ Non-selective (> 30% rows): Marginal benefit
- ❌ Low cardinality: No benefit, adds overhead
💼 Interview Questions & Expert Answers
Ace your Cassandra interview with these index questions!
Answer:
A secondary index in Cassandra allows you to query by non-primary key columns without using ALLOW FILTERING.
How It Works Internally:
- Hidden Table: Cassandra creates a hidden index table that maps indexed_column → partition_key
- Local Indexes: Each node maintains indexes only for its own data (no global index)
- Scatter-Gather: Query coordinator contacts ALL nodes to find matching rows
- Merge Results: Coordinator merges results from all nodes and returns to client
Example:
Key Limitation: Because indexes are local to each node, the coordinator must query ALL nodes, which can be slow in large clusters.
Answer:
The choice depends on your read/write ratio, cardinality, and performance requirements.
Use Secondary Index When:
- ✅ Read-heavy workload: More reads than writes
- ✅ High cardinality: Millions of unique values (email, username)
- ✅ Selective queries: Returns < 10% of rows
- ✅ Ad-hoc queries: Don't know all query patterns upfront
- ✅ Simple equality: WHERE column = value
Use Denormalization (Separate Table) When:
- ✅ Write-heavy workload: High INSERT/UPDATE volume
- ✅ Low cardinality: Few unique values (< 100)
- ✅ Predictable queries: Know exact query patterns
- ✅ Non-selective: Returns > 30% of rows
- ✅ Best performance: Fastest possible reads
Trade-off: Denormalization requires duplicate data and application-level write coordination, but provides better performance.
Answer: SASI (SSTable Attached Secondary Index) is an advanced index type supporting range queries and text search.
Key Differences:
| Feature | Regular Index | SASI Index |
|---|---|---|
| Equality | ✅ Supported | ✅ Supported |
| Range Queries | ❌ Not supported | ✅ Supported |
| LIKE Searches | ❌ Not supported | ✅ Supported |
| Case-Insensitive | ❌ Not supported | ✅ Configurable |
| Memory Usage | Higher | Lower |
SASI Examples:
Answer: Low cardinality columns have few unique values, making indexes inefficient and wasteful.
What is Low Cardinality?
Columns with only a few distinct values relative to the total number of rows.
Examples:
- ❌ gender: Only 2-3 values (M/F/Other)
- ❌ status: Only 3-5 values (active/inactive/suspended)
- ❌ boolean flags: Only 2 values (true/false)
- ❌ country: ~200 values (low for millions of rows)
Why It's Bad:
- Non-Selective Queries: Returns huge % of rows (e.g., 50% for gender='M')
- Coordinator Overhead: Must contact ALL nodes and merge millions of results
- No Performance Gain: Still scans millions of rows anyway
- Write Penalty: Index slows writes for zero benefit
- Storage Waste: Index takes disk space with no value
Better Alternatives:
- ✅ Denormalize: Create users_by_gender table
- ✅ Materialized View: Auto-maintained denormalization
- ✅ Application Filter: Fetch all, filter in code (small datasets)
- ✅ Composite Key: Make it part of primary key if possible
Rule of Thumb: Only index if column has > 1000 unique values AND queries return < 10% of rows.
Answer: Cassandra performs a background index build process across all nodes.
Index Creation Process:
- Schema Change: Index definition is added to schema and replicated via gossip
- Background Build: Each node independently scans its local SSTables
- Index Population: For each row, extract indexed_column → partition_key mapping
- Index Storage: Write index entries to hidden index table
- Compaction: Index SSTables are compacted like regular tables
What You'll See:
Performance Impact During Build:
- 🔥 CPU Usage: Spikes to 80-90% on all nodes
- 💾 Disk I/O: Heavy reads from SSTables
- ⏱️ Time: ~1-2 minutes per 1M rows
- 📊 Compaction: Pauses other compactions
Can You Query During Build?
- ✅ Yes, but: Queries may miss rows not yet indexed
- ⚠️ Partial Results: Only rows indexed so far are returned
- ✅ After Build: All queries return complete results
Best Practice:
🎓 Chapter Summary: Index Mastery
Congratulations! You now understand Cassandra Indexes at a production level!
Key Concepts Mastered:
- Secondary Indexes: Allow queries on non-primary key columns
- Local Indexes: Each node maintains indexes for its own data
- SASI Indexes: Support range queries, LIKE, and case-insensitive search
- Cardinality Matters: Only index high-cardinality columns
- Write Trade-off: Indexes add 10-30% overhead to writes
The Golden Rules:
1. High Cardinality Only
Don't index gender, status, or boolean fields!
2. Selective Queries
Indexes work best when returning < 10% of rows
3. Consider Denormalization
Often faster and more scalable than indexes
When to Use What:
- 🎯 Regular Index: High cardinality, equality queries (email, username)
- 🚀 SASI Index: Range queries, text search (price, name)
- 📦 Collection Index: CONTAINS queries on SET/LIST/MAP
- 🏗️ Denormalization: Low cardinality, write-heavy, best performance
- 🔍 External Search: Complex text search (use Elasticsearch)
🚀 You're now equipped to build blazing-fast queries with indexes!
Responsive Ad