Introduction

This is a critical area for database performance. While indexing is essential for fast reads, misused indexes can severely degrade write performance and consume unnecessary storage.
Here are 10 common indexing mistakes developers and junior DBAs make in SQL Server, along with the best practice to avoid them:
1. Creating Too Many Indexes
Mistake: Adding indexes on every column “just in case.”
Why it’s bad:
- Each index consumes storage and slows down
INSERT,UPDATE, andDELETEoperations. - SQL Server must maintain every index during data changes.
Best Practice:
Create indexes only for columns used frequently in filters (WHERE), joins, or sorts (ORDER BY). Use the Query Store or DMVs to identify truly beneficial indexes.
2. Ignoring Write Performance
Mistake: Focusing only on read/query speed and forgetting about DML overhead.
Why it’s bad:
Indexes improve reads but add extra cost to writes. SQL Server must update each relevant index.
Best Practice:
Balance read vs. write workload.
For high-insert workloads (e.g., OLTP), minimize nonclustered indexes.
3. Using Too Many Included Columns
Mistake: Adding every column to the INCLUDE() list to “cover” the query.
Why it’s bad:
- Increases index size and memory footprint.
- Can make maintenance jobs (like rebuilds) slower.
Best Practice:
Include only non-key columns needed for output. Avoid large data types (like NVARCHAR(MAX) or VARBINARY).
4. Not Considering Index Selectivity
Mistake: Indexing low-selectivity columns (e.g., Gender, IsActive, Status).
Why it’s bad:
- SQL Server may still perform full scans because the index doesn’t filter much data.
- Wastes storage and CPU.
Best Practice:
Choose high-selectivity columns (unique or nearly unique values) for effective filtering.
5. Ignoring Composite Index Column Order
Mistake: Misordering columns in a multi-column (composite) index.
Why it’s bad:
The index is only useful if the leading column(s) match the query’s filter or join predicate.
Best Practice:
Follow the leftmost prefix rule – order columns based on query usage:
WHERE <FirstColumn> = value AND <SecondColumn> BETWEEN...
should match (FirstColumn, SecondColumn) order in the index.
6. Duplicating Indexes
Mistake: Creating multiple indexes with overlapping key columns.
Why it’s bad:
- Wastes space and increases maintenance load.
- Confuses the optimizer, which must evaluate redundant indexes.
Best Practice:
Run this DMV to identify duplicate/overlapping indexes:
SELECT * FROM sys.dm_db_index_usage_stats;
and consolidate similar indexes into one optimized structure.
7. Forgetting to Rebuild or Reorganize Indexes
Mistake: Letting fragmentation build up over time.
Why it’s bad:
Fragmented indexes slow down reads and cause inefficient I/O.
Best Practice:
Set up regular maintenance:
ALTER INDEX ALL ON [TableName] REBUILD WITH (ONLINE=ON);
or use Ola Hallengren’s Index Maintenance Scripts (industry standard).
8. Not Updating Statistics
Mistake: Assuming index rebuild automatically fixes all performance issues.
Why it’s bad:
If statistics are outdated, SQL Server’s optimizer can still choose poor plans even with good indexes.
Best Practice:
Regularly update statistics:
EXEC sp_updatestats;
or enable AUTO_UPDATE_STATISTICS at the database level.
9. Ignoring Filtered Indexes
Mistake: Always using full-table indexes.
Why it’s bad:
Full indexes waste space when you only query a subset of rows.
Best Practice:
Use filtered indexes for partial data scenarios:
CREATE INDEX IX_Orders_Completed
ON Orders (OrderDate)
WHERE Status = 'Completed';
They save space and improve targeted performance.
10. Not Monitoring Index Usage
Mistake: Creating indexes but never checking if they’re actually used.
Why it’s bad:
Unused indexes waste resources and slow down writes.
Best Practice:
Identify unused or rarely used indexes:
SELECT OBJECT_NAME(i.object_id) AS TableName, i.name AS IndexName,
user_seeks, user_scans, user_lookups, user_updates
FROM sys.dm_db_index_usage_stats AS s
JOIN sys.indexes AS i
ON s.object_id = i.object_id AND s.index_id = i.index_id
ORDER BY user_seeks + user_scans + user_lookups ASC;
Drop or disable truly unused ones after confirming no dependencies.
Summary Table
| # | Common Mistake | Consequence | Best Practice |
|---|---|---|---|
| 1 | Too many indexes | Slow writes, high storage | Index only necessary columns |
| 2 | Ignoring writes | High DML cost | Balance reads vs. writes |
| 3 | Too many included columns | Large index size | Include minimal needed |
| 4 | Low-selectivity columns | Ineffective filters | Choose unique columns |
| 5 | Wrong column order | Index not used | Follow leftmost rule |
| 6 | Duplicate indexes | Wasted space | Consolidate similar indexes |
| 7 | Not rebuilding | Fragmentation | Schedule maintenance |
| 8 | Old statistics | Poor plans | Update stats regularly |
| 9 | Full-table indexes | Inefficient | Use filtered indexes |
| 10 | No monitoring | Unused indexes | Track and drop unused |
Bonus Tip
Use Database Engine Tuning Advisor (DTA) or Query Store to validate index changes before implementing them.
Always test in staging an index before implementing in Production as that index may helps one query but can harm another.
Discover more from Technology with Vivek Johari
Subscribe to get the latest posts sent to your email.



