index-strategies

Comprehensive guide to SQL Server index design and optimization.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "index-strategies" with this command: npx skills add josiahsiegel/claude-plugin-marketplace/josiahsiegel-claude-plugin-marketplace-index-strategies

Index Strategies

Comprehensive guide to SQL Server index design and optimization.

Quick Reference

Index Types

Type Description Best For

Clustered Table data order Primary access path, range scans

Nonclustered Separate structure Specific query patterns

Columnstore Column-based storage Analytics, aggregations

Filtered Partial index Well-known subsets

Covering All columns needed Avoiding key lookups

Clustered Index Guidelines

Ideal Clustered Key:

  • Narrow (small data type)

  • Unique or mostly unique

  • Ever-increasing (identity, sequential GUID)

  • Static (rarely updated)

-- Good: Identity column CREATE CLUSTERED INDEX CIX_Orders ON Orders(OrderID);

-- Good: Sequential GUID CREATE TABLE Orders ( OrderID UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() PRIMARY KEY CLUSTERED );

-- Avoid: Wide composite keys, frequently updated columns, GUIDs (NEWID)

Nonclustered Index Design

-- Basic index CREATE NONCLUSTERED INDEX IX_Orders_CustomerID ON Orders(CustomerID);

-- Covering index (avoids key lookup) CREATE NONCLUSTERED INDEX IX_Orders_CustomerID_Cover ON Orders(CustomerID) INCLUDE (OrderDate, TotalAmount, Status);

-- Filtered index (partial) CREATE NONCLUSTERED INDEX IX_Orders_Active ON Orders(CustomerID, OrderDate) WHERE Status = 'Active';

-- Descending order CREATE NONCLUSTERED INDEX IX_Orders_DateDesc ON Orders(OrderDate DESC, OrderID DESC);

Index Selection Guide

By Query Pattern

Pattern Recommended Index

WHERE Col = value

Nonclustered on Col

WHERE Col = v1 AND Col2 = v2

Nonclustered on (Col, Col2)

WHERE Col = v ORDER BY Col2

Nonclustered on (Col, Col2)

WHERE Col BETWEEN x AND y

Col as leftmost key

SELECT * WHERE Col = v

Clustered or covering NC

Large aggregations Columnstore

Specific subset queries Filtered index

Column Order in Composite Keys

-- Order matters! Left-to-right matching CREATE INDEX IX_Example ON Table(A, B, C);

-- These queries CAN use the index: WHERE A = 1 WHERE A = 1 AND B = 2 WHERE A = 1 AND B = 2 AND C = 3 WHERE A = 1 AND B > 5 ORDER BY B

-- These queries CANNOT use index seek: WHERE B = 2 -- A not specified WHERE B = 2 AND C = 3 -- A not specified WHERE A = 1 AND C = 3 -- B skipped (partial match only)

Columnstore Indexes

Clustered Columnstore

-- Best for data warehousing CREATE CLUSTERED COLUMNSTORE INDEX CCI_FactSales ON FactSales;

-- Ordered columnstore (SQL 2022+) CREATE CLUSTERED COLUMNSTORE INDEX CCI_FactSales ON FactSales ORDER (DateKey, ProductKey);

Nonclustered Columnstore

-- Hybrid OLTP/OLAP CREATE NONCLUSTERED COLUMNSTORE INDEX NCCI_Orders_Analysis ON Orders(OrderDate, ProductID, Quantity, Amount) WHERE Status = 'Completed';

Columnstore Best Practices

  • Load batches >= 102,400 rows - Creates compressed segments

  • Order data by filtered columns - Better segment elimination

  • Use REORGANIZE, not REBUILD - More efficient maintenance

  • Avoid frequent small updates - Causes deltastore fragmentation

  • Partition by date - Enables partition elimination

-- Maintenance ALTER INDEX CCI_FactSales ON FactSales REORGANIZE;

-- Check fragmentation SELECT object_name(object_id) AS TableName, index_id, avg_fragmentation_in_percent, fragment_count FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED');

Filtered Indexes

-- Index active orders only CREATE NONCLUSTERED INDEX IX_Orders_Active ON Orders(CustomerID, OrderDate) WHERE Status = 'Active';

-- Index non-NULL values CREATE UNIQUE INDEX IX_Users_Email ON Users(Email) WHERE Email IS NOT NULL;

-- Constraints: -- - Cannot use variable in filter -- - Query WHERE must match or be subset of filter WHERE -- - May cause parameter sniffing issues

Covering Indexes

-- Eliminate key lookups -- Original: Index on CustomerID, query selects OrderDate, Amount -- Execution plan shows Key Lookup

-- Solution: Covering index CREATE INDEX IX_Orders_CustomerID_Cover ON Orders(CustomerID) INCLUDE (OrderDate, Amount, Status);

-- INCLUDE columns: -- - Not in key (not sorted) -- - Stored at leaf level only -- - Don't contribute to 900-byte key limit -- - Perfect for frequently selected columns

Index Maintenance

Fragmentation Guidelines

Fragmentation % Action

< 5% None needed

5-30% REORGANIZE

30% REBUILD

-- Reorganize (online, minimal locking) ALTER INDEX IX_Orders_CustomerID ON Orders REORGANIZE;

-- Rebuild (offline by default, more thorough) ALTER INDEX IX_Orders_CustomerID ON Orders REBUILD;

-- Online rebuild (Enterprise Edition) ALTER INDEX IX_Orders_CustomerID ON Orders REBUILD WITH (ONLINE = ON);

-- Resumable rebuild (SQL 2017+) ALTER INDEX IX_Orders_CustomerID ON Orders REBUILD WITH (ONLINE = ON, RESUMABLE = ON, MAX_DURATION = 60);

-- Resume interrupted rebuild ALTER INDEX IX_Orders_CustomerID ON Orders RESUME;

Statistics Update

-- Update after index changes UPDATE STATISTICS Orders;

-- Full scan for accurate stats UPDATE STATISTICS Orders WITH FULLSCAN;

-- Check last update SELECT OBJECT_NAME(object_id) AS TableName, name AS StatsName, STATS_DATE(object_id, stats_id) AS LastUpdated FROM sys.stats WHERE object_id = OBJECT_ID('Orders');

Performance Monitoring

Index Usage Stats

SELECT OBJECT_NAME(i.object_id) AS TableName, i.name AS IndexName, ius.user_seeks, ius.user_scans, ius.user_lookups, ius.user_updates FROM sys.indexes i LEFT JOIN sys.dm_db_index_usage_stats ius ON i.object_id = ius.object_id AND i.index_id = ius.index_id WHERE OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1 ORDER BY ius.user_seeks + ius.user_scans DESC;

Missing Index Recommendations

SELECT migs.avg_user_impact AS ImpactPercent, mid.statement AS TableName, mid.equality_columns, mid.inequality_columns, mid.included_columns FROM sys.dm_db_missing_index_groups mig JOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handle JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle ORDER BY migs.avg_user_impact DESC;

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

tailwindcss-advanced-layouts

No summary provided by upstream source.

Repository SourceNeeds Review
General

tailwindcss-animations

No summary provided by upstream source.

Repository SourceNeeds Review
General

tailwindcss-mobile-first

No summary provided by upstream source.

Repository SourceNeeds Review
General

docker-best-practices

No summary provided by upstream source.

Repository SourceNeeds Review