Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

nodetool rebuild_index

Rebuilds secondary indexes for a table.


Terminal window
nodetool [connection_options] rebuild_index <keyspace> <table> [index_name...]

See connection options for connection options.


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 FILTERING is used)
  • Fail with an error

Plan accordingly for production systems. See Application Impact for details.


ArgumentDescription
keyspaceTarget keyspace name (required)
tableTarget table name (required)
index_nameOptional: specific index names to rebuild. If omitted, rebuilds ALL indexes on the table

Understanding the rebuild process helps in planning and risk assessment:

  1. Index marked as building — index queries return incomplete results or fail
  2. Full table scan begins — every SSTable is read sequentially; each row's indexed column is extracted
  3. New index entries created — index SSTables are written; compaction may occur on index SSTables
  4. Index marked as built — index queries resume normal operation

Query TypeBehavior During Rebuild
Query using the rebuilding indexReturns incomplete results or fails
Query using ALLOW FILTERINGWorks but extremely slow (full scan)
Queries not using the indexUnaffected
Writes to the tableContinue normally, indexed in new index
# Common error during rebuild
Unable 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)

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

Rebuild time depends on several factors:

FactorImpact
Table size (data volume)Linear - 2x data = ~2x time
Number of SSTablesMore SSTables = more I/O overhead
Disk speedSSD vs HDD makes significant difference
Concurrent operationsOther compactions/repairs slow rebuild
Index typeSASI indexes take longer than regular 2i
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 days

Estimates Are Approximate

Actual times vary significantly based on hardware, cluster load, and data characteristics. Always test in a non-production environment first.

Terminal window
# Watch rebuild progress (shows as "Secondary index build")
watch -n 10 'nodetool compactionstats'
# Check system log for progress
tail -f /var/log/cassandra/system.log | grep -i "index"
# Detailed progress
nodetool 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 : 0h15m32s

Terminal window
# Rebuilds every index on the table
nodetool rebuild_index my_keyspace users
# Equivalent to rebuilding: users_email_idx, users_status_idx, etc.
Terminal window
# Rebuild only the email index
nodetool rebuild_index my_keyspace users users_email_idx
Terminal window
# Rebuild two specific indexes
nodetool rebuild_index my_keyspace users users_email_idx users_status_idx
Terminal window
# List indexes on a table
cqlsh -e "DESCRIBE TABLE my_keyspace.users;" | grep INDEX
# Or query schema directly
cqlsh -e "SELECT index_name FROM system_schema.indexes
WHERE keyspace_name = 'my_keyspace' AND table_name = 'users';"

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
Terminal window
# Verify index inconsistency
cqlsh -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 fix
nodetool rebuild_index my_keyspace users users_email_idx

Why needed: Snapshots include index SSTables, but they may not be consistent with the restored data state.

Terminal window
# After restoring a table from snapshot
nodetool refresh my_keyspace users
# Rebuild all indexes to ensure consistency
nodetool rebuild_index my_keyspace users

Why needed: New node may have index entries without corresponding base data or vice versa.

Terminal window
# After replacing a node and streaming data
nodetool rebuild_index my_keyspace users

Why needed: After changing from regular secondary index to SASI or SAI.

Terminal window
# After altering index configuration
nodetool rebuild_index my_keyspace users new_index_name

Symptoms in logs:

ERROR - Corrupt index segment detected for users_email_idx
WARN - Index users_email_idx may be inconsistent
Terminal window
# Rebuild the corrupted index
nodetool rebuild_index my_keyspace users users_email_idx

Avoid These Situations

Don't use rebuild_index when:

  1. Index is working correctly - Rebuilding a healthy index wastes resources
  2. During peak traffic - Causes performance degradation and query failures
  3. Without notifying application teams - Will cause application errors
  4. On very large tables without estimation - Could take days
  5. When simpler fixes exist - Sometimes repair or compaction is sufficient

pre_rebuild_check.sh
#!/bin/bash
KEYSPACE="$1"
TABLE="$2"
INDEX="$3"
echo "=== Pre-Rebuild Safety Check ==="
# 1. Check table size
echo ""
echo "1. Table size estimation:"
nodetool tablestats $KEYSPACE.$TABLE | grep "Space used"
# 2. List indexes
echo ""
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 load
echo ""
echo "3. Current cluster load:"
nodetool tpstats | head -20
# 4. Check pending compactions
echo ""
echo "4. Pending compactions:"
nodetool compactionstats
# 5. Estimate time
size_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"
safe_rebuild_index.sh
#!/bin/bash
KEYSPACE="$1"
TABLE="$2"
INDEX="$3"
echo "=== Safe Index Rebuild ==="
echo "Target: $KEYSPACE.$TABLE ${INDEX:-'(all indexes)'}"
echo ""
# Confirm
read -p "This will make the index unavailable. Continue? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "Aborted."
exit 1
fi
# Record start time
START_TIME=$(date +%s)
echo ""
echo "Started at: $(date)"
# Start rebuild
echo ""
echo "Initiating rebuild..."
nodetool rebuild_index $KEYSPACE $TABLE $INDEX &
REBUILD_PID=$!
# Monitor progress
echo ""
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 30
done
# Calculate duration
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo ""
echo "=== Rebuild Complete ==="
echo "Duration: $((DURATION / 60)) minutes $((DURATION % 60)) seconds"
# Verify index is ready
echo ""
echo "Verifying index is ready..."
# Test query (modify for your schema)
echo "Run a test query to verify index is working"

ResourceImpact LevelNotes
Disk I/OHIGHFull table scan reads all SSTables
CPUModerateIndex entry creation and sorting
MemoryLow-ModerateBuffers for reading and writing
NetworkNoneLocal operation only
Disk SpaceTemporary increaseOld + new index until compaction
OperationAffected?Details
Normal reads (no index)MinimalMay compete for I/O
Normal writesMinimalWrites continue, new data indexed
CompactionSlowedCompetes for resources
RepairShould avoidDon't run simultaneously
Backup/SnapshotCan proceedBut indexes may be mid-rebuild

Node-Local Operation

rebuild_index only rebuilds indexes on the node where it's executed. For complete cluster-wide rebuild, run on every node.

rebuild_index_cluster.sh
#!/bin/bash
KEYSPACE="$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_NODES
done
echo ""
echo "=== Cluster-wide rebuild complete ==="
ApproachProsCons
Rolling (one at a time)Lower cluster impact, saferTakes longer
Parallel (all at once)Faster total timeHigher cluster stress, all indexes unavailable

Recommendation: Use rolling rebuild for production systems.


Terminal window
# Check logs for completion message
grep -i "index build complete\|finished building" /var/log/cassandra/system.log | tail -5
# Verify no pending index builds
nodetool compactionstats | grep -i "secondary index"
# Should return empty
Terminal window
# Run a query that uses the index
cqlsh -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"
Terminal window
# Query with index
cqlsh -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 match

Terminal window
# Check if rebuild is actually progressing
watch -n 30 'nodetool compactionstats | grep -i index'
# Check for resource contention
nodetool tpstats | grep -i blocked
# Consider pausing other operations
nodetool disableautocompaction my_keyspace my_table
# ... rebuild ...
nodetool enableautocompaction my_keyspace my_table
Terminal window
# Check Cassandra logs for errors
tail -100 /var/log/cassandra/system.log | grep -i "error\|exception\|index"
# Check thread pools for issues
nodetool tpstats
# If truly stuck, may need to restart (use with caution)
# The rebuild will restart from the beginning

Index Still Returning Bad Results After Rebuild

Section titled “Index Still Returning Bad Results After Rebuild”
Terminal window
# Verify rebuild completed on ALL nodes
for 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 recreate
cqlsh -e "DROP INDEX my_keyspace.users_email_idx;"
cqlsh -e "CREATE INDEX users_email_idx ON my_keyspace.users (email);"
Terminal window
# Rebuild creates new index files before removing old ones
# Need approximately 2x index size temporarily
# Check disk space
df -h /var/lib/cassandra
# If space is tight, rebuild indexes one at a time
# and run compaction between each
nodetool rebuild_index my_keyspace users idx1
nodetool compact my_keyspace users
nodetool rebuild_index my_keyspace users idx2

Index Rebuild Guidelines

  1. Estimate first - Know how long it will take before starting
  2. Communicate - Notify all stakeholders about index unavailability
  3. Maintenance window - Prefer low-traffic periods
  4. One at a time - Rebuild indexes sequentially, not in parallel
  5. Monitor throughout - Watch compactionstats and logs
  6. Verify after - Test queries to confirm index is working
  7. 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+)

CommandRelationship
compactionstatsMonitor rebuild progress
tablestatsCheck table size before rebuild
repairAlternative for some consistency issues
compactMay help with some index issues
disableautocompactionReduce resource contention
enableautocompactionRe-enable after rebuild