nodetool rebuild_index
Rebuilds secondary indexes for a table.
Synopsis
Section titled “Synopsis”nodetool [connection_options] rebuild_index <keyspace> <table> [index_name...]See connection options for connection options.
Description
Section titled “Description”nodetool rebuild_index reconstructs one or more secondary indexes on a table by scanning all data in the base table and regenerating the index entries. This operation is necessary when indexes become corrupted, out of sync with the base data, or after certain recovery scenarios.
Critical: Index Unavailability During Rebuild
The index becomes unavailable for queries during the rebuild process. Any queries that rely on the index will either:
- Return incomplete/partial results
- Fall back to inefficient full table scans (if
ALLOW FILTERINGis used) - Fail with an error
Plan accordingly for production systems. See Application Impact for details.
Arguments
Section titled “Arguments”| Argument | Description |
|---|---|
keyspace | Target keyspace name (required) |
table | Target table name (required) |
index_name | Optional: specific index names to rebuild. If omitted, rebuilds ALL indexes on the table |
What Happens During Index Rebuild
Section titled “What Happens During Index Rebuild”Understanding the rebuild process helps in planning and risk assessment:
Step-by-Step Process
Section titled “Step-by-Step Process”- Index marked as building — index queries return incomplete results or fail
- Full table scan begins — every SSTable is read sequentially; each row's indexed column is extracted
- New index entries created — index SSTables are written; compaction may occur on index SSTables
- Index marked as built — index queries resume normal operation
Application Impact
Section titled “Application Impact”What Happens to Queries During Rebuild
Section titled “What Happens to Queries During Rebuild”| Query Type | Behavior During Rebuild |
|---|---|
| Query using the rebuilding index | Returns incomplete results or fails |
Query using ALLOW FILTERING | Works but extremely slow (full scan) |
| Queries not using the index | Unaffected |
| Writes to the table | Continue normally, indexed in new index |
Error Messages Applications May See
Section titled “Error Messages Applications May See”# Common error during rebuildUnable to execute query: Index 'my_index' is not ready for use
# Or queries may silently return partial results# (more dangerous - appears to work but data is incomplete)Application Preparation Checklist
Section titled “Application Preparation Checklist”Before running rebuild_index in production:
- Notify application teams - They need to handle index unavailability
- Implement fallback logic - Applications should handle missing index gracefully
- Consider circuit breakers - Disable features that depend on the index
- Plan maintenance window - If possible, rebuild during low-traffic periods
- Estimate rebuild time - See Duration Estimation
Duration Estimation
Section titled “Duration Estimation”Rebuild time depends on several factors:
Factors Affecting Duration
Section titled “Factors Affecting Duration”| Factor | Impact |
|---|---|
| Table size (data volume) | Linear - 2x data = ~2x time |
| Number of SSTables | More SSTables = more I/O overhead |
| Disk speed | SSD vs HDD makes significant difference |
| Concurrent operations | Other compactions/repairs slow rebuild |
| Index type | SASI indexes take longer than regular 2i |
Rough Estimation Formula
Section titled “Rough Estimation Formula”Estimated Time ≈ (Table Size in GB) × (1-5 minutes per GB)
Examples:- 10 GB table, SSD: ~10-20 minutes- 100 GB table, SSD: ~2-4 hours- 100 GB table, HDD: ~4-8 hours- 1 TB table: ~1-2 daysEstimates Are Approximate
Actual times vary significantly based on hardware, cluster load, and data characteristics. Always test in a non-production environment first.
Checking Progress
Section titled “Checking Progress”# Watch rebuild progress (shows as "Secondary index build")watch -n 10 'nodetool compactionstats'
# Check system log for progresstail -f /var/log/cassandra/system.log | grep -i "index"
# Detailed progressnodetool compactionstats | grep -A 5 "Secondary index"Sample compactionstats output during rebuild:
pending tasks: 1- Secondary index build my_keyspace my_table 45678901234 42%Active compaction remaining time : 0h15m32sExamples
Section titled “Examples”Rebuild All Indexes on a Table
Section titled “Rebuild All Indexes on a Table”# Rebuilds every index on the tablenodetool rebuild_index my_keyspace users
# Equivalent to rebuilding: users_email_idx, users_status_idx, etc.Rebuild Specific Index
Section titled “Rebuild Specific Index”# Rebuild only the email indexnodetool rebuild_index my_keyspace users users_email_idxRebuild Multiple Specific Indexes
Section titled “Rebuild Multiple Specific Indexes”# Rebuild two specific indexesnodetool rebuild_index my_keyspace users users_email_idx users_status_idxFind Index Names First
Section titled “Find Index Names First”# List indexes on a tablecqlsh -e "DESCRIBE TABLE my_keyspace.users;" | grep INDEX
# Or query schema directlycqlsh -e "SELECT index_name FROM system_schema.indexes WHERE keyspace_name = 'my_keyspace' AND table_name = 'users';"When to Use
Section titled “When to Use”Scenario 1: Index Returning Incorrect Results
Section titled “Scenario 1: Index Returning Incorrect Results”Symptoms:
- Queries using the index return fewer results than expected
- Results don't match direct queries with
ALLOW FILTERING - Index appears to be missing data
# Verify index inconsistencycqlsh -e "SELECT COUNT(*) FROM my_keyspace.users WHERE email = 'test@example.com';"# Returns 0
cqlsh -e "SELECT COUNT(*) FROM my_keyspace.users WHERE email = 'test@example.com' ALLOW FILTERING;"# Returns 5 (correct)
# Rebuild to fixnodetool rebuild_index my_keyspace users users_email_idxScenario 2: After Restoring from Backup
Section titled “Scenario 2: After Restoring from Backup”Why needed: Snapshots include index SSTables, but they may not be consistent with the restored data state.
# After restoring a table from snapshotnodetool refresh my_keyspace users
# Rebuild all indexes to ensure consistencynodetool rebuild_index my_keyspace usersScenario 3: After Node Replacement
Section titled “Scenario 3: After Node Replacement”Why needed: New node may have index entries without corresponding base data or vice versa.
# After replacing a node and streaming datanodetool rebuild_index my_keyspace usersScenario 4: Upgrading Index Type
Section titled “Scenario 4: Upgrading Index Type”Why needed: After changing from regular secondary index to SASI or SAI.
# After altering index configurationnodetool rebuild_index my_keyspace users new_index_nameScenario 5: Corruption Detected in Logs
Section titled “Scenario 5: Corruption Detected in Logs”Symptoms in logs:
ERROR - Corrupt index segment detected for users_email_idxWARN - Index users_email_idx may be inconsistent# Rebuild the corrupted indexnodetool rebuild_index my_keyspace users users_email_idxWhen NOT to Use
Section titled “When NOT to Use”Avoid These Situations
Don't use rebuild_index when:
- Index is working correctly - Rebuilding a healthy index wastes resources
- During peak traffic - Causes performance degradation and query failures
- Without notifying application teams - Will cause application errors
- On very large tables without estimation - Could take days
- When simpler fixes exist - Sometimes repair or compaction is sufficient
Safe Execution Workflow
Section titled “Safe Execution Workflow”Pre-Rebuild Checklist
Section titled “Pre-Rebuild Checklist”#!/bin/bashKEYSPACE="$1"TABLE="$2"INDEX="$3"
echo "=== Pre-Rebuild Safety Check ==="
# 1. Check table sizeecho ""echo "1. Table size estimation:"nodetool tablestats $KEYSPACE.$TABLE | grep "Space used"
# 2. List indexesecho ""echo "2. Indexes on table:"cqlsh -e "SELECT index_name FROM system_schema.indexes WHERE keyspace_name = '$KEYSPACE' AND table_name = '$TABLE';"
# 3. Check current cluster loadecho ""echo "3. Current cluster load:"nodetool tpstats | head -20
# 4. Check pending compactionsecho ""echo "4. Pending compactions:"nodetool compactionstats
# 5. Estimate timesize_bytes=$(nodetool tablestats $KEYSPACE.$TABLE 2>/dev/null | grep "Space used (live)" | awk '{print $4}')size_gb=$((size_bytes / 1073741824))echo ""echo "5. Estimated rebuild time: $((size_gb * 2)) - $((size_gb * 5)) minutes"
echo ""echo "=== Review above before proceeding ==="echo "Command to execute: nodetool rebuild_index $KEYSPACE $TABLE $INDEX"Controlled Rebuild with Monitoring
Section titled “Controlled Rebuild with Monitoring”#!/bin/bashKEYSPACE="$1"TABLE="$2"INDEX="$3"
echo "=== Safe Index Rebuild ==="echo "Target: $KEYSPACE.$TABLE ${INDEX:-'(all indexes)'}"echo ""
# Confirmread -p "This will make the index unavailable. Continue? (yes/no): " confirmif [ "$confirm" != "yes" ]; then echo "Aborted." exit 1fi
# Record start timeSTART_TIME=$(date +%s)echo ""echo "Started at: $(date)"
# Start rebuildecho ""echo "Initiating rebuild..."nodetool rebuild_index $KEYSPACE $TABLE $INDEX &REBUILD_PID=$!
# Monitor progressecho ""echo "Monitoring progress (Ctrl+C to stop monitoring, rebuild continues)..."while kill -0 $REBUILD_PID 2>/dev/null; do progress=$(nodetool compactionstats 2>/dev/null | grep -i "secondary index" | tail -1) if [ -n "$progress" ]; then echo "$(date '+%H:%M:%S') - $progress" else echo "$(date '+%H:%M:%S') - Waiting for rebuild to appear in compactionstats..." fi sleep 30done
# Calculate durationEND_TIME=$(date +%s)DURATION=$((END_TIME - START_TIME))echo ""echo "=== Rebuild Complete ==="echo "Duration: $((DURATION / 60)) minutes $((DURATION % 60)) seconds"
# Verify index is readyecho ""echo "Verifying index is ready..."# Test query (modify for your schema)echo "Run a test query to verify index is working"Impact Assessment
Section titled “Impact Assessment”Resource Usage During Rebuild
Section titled “Resource Usage During Rebuild”| Resource | Impact Level | Notes |
|---|---|---|
| Disk I/O | HIGH | Full table scan reads all SSTables |
| CPU | Moderate | Index entry creation and sorting |
| Memory | Low-Moderate | Buffers for reading and writing |
| Network | None | Local operation only |
| Disk Space | Temporary increase | Old + new index until compaction |
Impact on Other Operations
Section titled “Impact on Other Operations”| Operation | Affected? | Details |
|---|---|---|
| Normal reads (no index) | Minimal | May compete for I/O |
| Normal writes | Minimal | Writes continue, new data indexed |
| Compaction | Slowed | Competes for resources |
| Repair | Should avoid | Don't run simultaneously |
| Backup/Snapshot | Can proceed | But indexes may be mid-rebuild |
Cluster-Wide Considerations
Section titled “Cluster-Wide Considerations”Must Run on Each Node
Section titled “Must Run on Each Node”Node-Local Operation
rebuild_index only rebuilds indexes on the node where it's executed. For complete cluster-wide rebuild, run on every node.
#!/bin/bashKEYSPACE="$1"TABLE="$2"INDEX="$3"DELAY_BETWEEN_NODES=300 # 5 minutes
echo "=== Cluster-Wide Index Rebuild ==="echo "Target: $KEYSPACE.$TABLE ${INDEX:-'(all indexes)'}"# Get list of node IPs from local nodetool status
nodes=$(nodetool status | grep "^UN" | awk '{print $2}')
for node in $nodes; do echo "" echo "$(date): Starting rebuild on $node..." ssh "$node" "nodetool rebuild_index $KEYSPACE $TABLE $INDEX"
# Wait for completion while ssh "$node" "nodetool compactionstats 2>/dev/null | grep -qi "secondary index"; do" echo " Waiting for rebuild to complete on $node..." sleep 60 done
echo "$(date): Rebuild complete on $node"
# Wait before next node (optional, allows cache warming) echo "Waiting ${DELAY_BETWEEN_NODES}s before next node..." sleep $DELAY_BETWEEN_NODESdone
echo ""echo "=== Cluster-wide rebuild complete ==="Rolling vs Parallel Rebuild
Section titled “Rolling vs Parallel Rebuild”| Approach | Pros | Cons |
|---|---|---|
| Rolling (one at a time) | Lower cluster impact, safer | Takes longer |
| Parallel (all at once) | Faster total time | Higher cluster stress, all indexes unavailable |
Recommendation: Use rolling rebuild for production systems.
Verification After Rebuild
Section titled “Verification After Rebuild”Confirm Rebuild Completed
Section titled “Confirm Rebuild Completed”# Check logs for completion messagegrep -i "index build complete\|finished building" /var/log/cassandra/system.log | tail -5
# Verify no pending index buildsnodetool compactionstats | grep -i "secondary index"# Should return emptyTest Index Functionality
Section titled “Test Index Functionality”# Run a query that uses the indexcqlsh -e "TRACING ON; SELECT * FROM my_keyspace.users WHERE email = 'test@example.com';"
# Verify the trace shows index usage, not full scan# Look for: "Index scan" rather than "Seq scan"Compare Results
Section titled “Compare Results”# Query with indexcqlsh -e "SELECT COUNT(*) FROM my_keyspace.users WHERE email = 'test@example.com';"
# Query with ALLOW FILTERING (bypasses index)cqlsh -e "SELECT COUNT(*) FROM my_keyspace.users WHERE email = 'test@example.com' ALLOW FILTERING;"
# Results should matchTroubleshooting
Section titled “Troubleshooting”Rebuild Taking Too Long
Section titled “Rebuild Taking Too Long”# Check if rebuild is actually progressingwatch -n 30 'nodetool compactionstats | grep -i index'
# Check for resource contentionnodetool tpstats | grep -i blocked
# Consider pausing other operationsnodetool disableautocompaction my_keyspace my_table# ... rebuild ...nodetool enableautocompaction my_keyspace my_tableRebuild Appears Stuck
Section titled “Rebuild Appears Stuck”# Check Cassandra logs for errorstail -100 /var/log/cassandra/system.log | grep -i "error\|exception\|index"
# Check thread pools for issuesnodetool tpstats
# If truly stuck, may need to restart (use with caution)# The rebuild will restart from the beginningIndex Still Returning Bad Results After Rebuild
Section titled “Index Still Returning Bad Results After Rebuild”# Verify rebuild completed on ALL nodesfor node in $(nodetool status | grep "^UN" | awk '{print $2}'); do echo "Checking $node..." ssh "$node" "nodetool compactionstats | grep -i "secondary index" || echo " No active rebuilds""done
# If already complete everywhere, may need to drop and recreatecqlsh -e "DROP INDEX my_keyspace.users_email_idx;"cqlsh -e "CREATE INDEX users_email_idx ON my_keyspace.users (email);"Out of Disk Space During Rebuild
Section titled “Out of Disk Space During Rebuild”# Rebuild creates new index files before removing old ones# Need approximately 2x index size temporarily
# Check disk spacedf -h /var/lib/cassandra
# If space is tight, rebuild indexes one at a time# and run compaction between eachnodetool rebuild_index my_keyspace users idx1nodetool compact my_keyspace usersnodetool rebuild_index my_keyspace users idx2Best Practices
Section titled “Best Practices”Index Rebuild Guidelines
- Estimate first - Know how long it will take before starting
- Communicate - Notify all stakeholders about index unavailability
- Maintenance window - Prefer low-traffic periods
- One at a time - Rebuild indexes sequentially, not in parallel
- Monitor throughout - Watch compactionstats and logs
- Verify after - Test queries to confirm index is working
- Document - Record when and why rebuilds were performed
Production Precautions
- Never rebuild without planning - Applications will see failures
- Test in staging first - Understand timing and behavior
- Have rollback plan - Know what to do if rebuild fails
- Consider alternatives - Sometimes repair or compaction is enough
- Check disk space - Need ~2x index size temporarily
Alternative Approaches
Before rebuilding, consider if these alternatives might help:
- Run repair - Fixes consistency issues that might affect index
- Run compaction - May resolve some index inconsistencies
- Drop and recreate - Sometimes faster for small tables
- SAI indexes - Consider migrating to Storage Attached Indexes (Cassandra 4.0+)
Related Commands
Section titled “Related Commands”| Command | Relationship |
|---|---|
| compactionstats | Monitor rebuild progress |
| tablestats | Check table size before rebuild |
| repair | Alternative for some consistency issues |
| compact | May help with some index issues |
| disableautocompaction | Reduce resource contention |
| enableautocompaction | Re-enable after rebuild |