SQL Server索引 #
一、索引概述 #
1.1 什么是索引 #
索引是数据库中用于加速查询的数据结构,类似于书籍的目录。通过索引可以快速定位数据,而不必扫描整个表。
text
索引作用:
├── 加速查询
├── 强制唯一性
├── 加速排序
└── 加速连接
索引代价:
├── 占用存储空间
├── 降低INSERT/UPDATE/DELETE速度
└── 需要维护
1.2 索引类型 #
text
SQL Server索引类型
├── 聚集索引(Clustered)
│ └── 表数据按索引顺序存储
├── 非聚集索引(Nonclustered)
│ └── 独立存储,包含指向数据的指针
├── 列存储索引(Columnstore)
│ └── 列式存储,适合分析查询
├── 全文索引(Full-text)
│ └── 全文搜索
├── 空间索引(Spatial)
│ └── 地理空间数据
├── XML索引
│ └── XML数据
└── 筛选索引(Filtered)
└── 部分数据索引
二、聚集索引 #
2.1 聚集索引特点 #
text
聚集索引特点:
├── 每个表只能有一个聚集索引
├── 表数据按聚集索引键值排序存储
├── 聚集索引的叶节点就是数据页
├── 主键默认创建聚集索引
└── 适合范围查询和排序
2.2 创建聚集索引 #
sql
-- 创建表时定义主键(自动创建聚集索引)
CREATE TABLE users (
id INT PRIMARY KEY,
name NVARCHAR(50),
email VARCHAR(100)
);
-- 显式创建聚集索引
CREATE CLUSTERED INDEX ix_users_id ON users(id);
-- 创建聚集索引并指定选项
CREATE CLUSTERED INDEX ix_users_created ON users(created_at)
WITH (
PAD_INDEX = ON,
FILLFACTOR = 80,
SORT_IN_TEMPDB = ON,
STATISTICS_NORECOMPUTE = OFF,
DROP_EXISTING = ON,
ONLINE = ON
);
2.3 聚集索引设计原则 #
text
聚集索引选择原则:
├── 选择唯一或高选择性的列
├── 选择经常用于范围查询的列
├── 选择经常用于ORDER BY的列
├── 选择经常用于GROUP BY的列
├── 选择窄列(占用空间小)
├── 选择静态列(很少更新)
└── 避免选择频繁更新的列
推荐:
├── 自增ID列
├── 日期时间列(如created_at)
└── 复合键(如(user_id, order_date))
三、非聚集索引 #
3.1 非聚集索引特点 #
text
非聚集索引特点:
├── 每个表可以有多个非聚集索引
├── 独立于表数据存储
├── 包含索引键和行定位符
├── 叶节点指向数据行
└── 适合精确查找
3.2 创建非聚集索引 #
sql
-- 创建简单非聚集索引
CREATE INDEX ix_users_email ON users(email);
-- 创建复合索引
CREATE INDEX ix_users_name_age ON users(name, age);
-- 创建唯一索引
CREATE UNIQUE INDEX ix_users_email_unique ON users(email);
-- 创建降序索引
CREATE INDEX ix_users_salary_desc ON users(salary DESC);
-- 创建包含列索引
CREATE INDEX ix_users_department ON users(department_id)
INCLUDE (name, salary);
3.3 索引包含列 #
sql
-- 包含列索引(覆盖索引)
CREATE INDEX ix_orders_user_date ON orders(user_id, order_date)
INCLUDE (amount, status);
-- 查询可以利用覆盖索引
SELECT user_id, order_date, amount, status
FROM orders
WHERE user_id = 1;
3.4 筛选索引 #
sql
-- 筛选索引:只索引部分数据
CREATE INDEX ix_users_active ON users(department_id)
WHERE status = 1;
-- 筛选唯一索引
CREATE UNIQUE INDEX ix_users_email_active ON users(email)
WHERE status = 1;
四、列存储索引 #
4.1 列存储索引特点 #
text
列存储索引特点:
├── 列式存储
├── 高压缩率
├── 适合分析查询(OLAP)
├── 批量插入性能好
└── 单行更新性能差
4.2 创建列存储索引 #
sql
-- 创建聚集列存储索引
CREATE CLUSTERED COLUMNSTORE INDEX ix_sales_columnstore
ON sales;
-- 创建非聚集列存储索引
CREATE NONCLUSTERED COLUMNSTORE INDEX ix_users_columnstore
ON users (age, salary, department_id);
-- 列存储索引适合的查询
SELECT
department_id,
AVG(salary),
COUNT(*)
FROM users
GROUP BY department_id;
五、全文索引 #
5.1 创建全文目录 #
sql
-- 创建全文目录
CREATE FULLTEXT CATALOG ft_catalog AS DEFAULT;
-- 创建全文索引
CREATE FULLTEXT INDEX ON products(name, description)
KEY INDEX pk_products
ON ft_catalog
WITH STOPLIST = SYSTEM;
-- 使用全文搜索
SELECT * FROM products
WHERE CONTAINS(name, 'laptop');
SELECT * FROM products
WHERE FREETEXT(description, 'high performance laptop');
5.2 全文搜索语法 #
sql
-- CONTAINS:精确匹配
SELECT * FROM products
WHERE CONTAINS(name, '"laptop"');
-- 使用AND/OR
SELECT * FROM products
WHERE CONTAINS(name, 'laptop AND computer');
-- 使用通配符
SELECT * FROM products
WHERE CONTAINS(name, '"lap*"');
-- FREETEXT:自然语言搜索
SELECT * FROM products
WHERE FREETEXT(name, 'good laptop');
六、索引维护 #
6.1 重建索引 #
sql
-- 重建单个索引
ALTER INDEX ix_users_email ON users REBUILD;
-- 重建所有索引
ALTER INDEX ALL ON users REBUILD;
-- 重建并设置选项
ALTER INDEX ix_users_email ON users
REBUILD WITH (
FILLFACTOR = 80,
ONLINE = ON,
SORT_IN_TEMPDB = ON
);
6.2 重组索引 #
sql
-- 重组索引(轻量级维护)
ALTER INDEX ix_users_email ON users REORGANIZE;
-- 重组所有索引
ALTER INDEX ALL ON users REORGANIZE;
6.3 索引碎片整理 #
sql
-- 查看索引碎片
SELECT
OBJECT_NAME(i.object_id) AS table_name,
i.name AS index_name,
ips.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
INNER JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 10;
-- 碎片处理建议:
-- < 5%:不需要处理
-- 5% - 30%:重组
-- > 30%:重建
七、索引管理 #
7.1 查看索引 #
sql
-- 查看表索引
EXEC sp_helpindex 'users';
-- 查看索引详细信息
SELECT
t.name AS table_name,
i.name AS index_name,
i.type_desc,
i.is_unique,
i.is_primary_key
FROM sys.indexes i
INNER JOIN sys.tables t ON i.object_id = t.object_id
WHERE t.name = 'users';
7.2 删除索引 #
sql
-- 删除索引
DROP INDEX ix_users_email ON users;
-- 安全删除
IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'ix_users_email' AND object_id = OBJECT_ID('users'))
DROP INDEX ix_users_email ON users;
八、索引优化建议 #
8.1 索引设计原则 #
text
索引设计原则:
├── 为WHERE子句列创建索引
├── 为JOIN列创建索引
├── 为ORDER BY列创建索引
├── 使用覆盖索引减少IO
├── 复合索引注意列顺序
├── 避免过度索引
├── 定期维护索引碎片
└── 更新统计信息
8.2 缺失索引查询 #
sql
-- 查看缺失索引建议
SELECT
mid.statement AS table_name,
mid.equality_columns,
mid.inequality_columns,
mid.included_columns,
migs.user_seeks,
migs.avg_user_impact
FROM sys.dm_db_missing_index_details mid
INNER JOIN sys.dm_db_missing_index_groups mig ON mid.index_handle = mig.index_handle
INNER JOIN sys.dm_db_missing_index_group_stats migs ON mig.index_group_handle = migs.group_handle
ORDER BY migs.avg_user_impact DESC;
九、总结 #
索引要点:
| 类型 | 说明 | 适用场景 |
|---|---|---|
| 聚集索引 | 数据按索引排序 | 主键、范围查询 |
| 非聚集索引 | 独立存储 | 精确查找 |
| 列存储索引 | 列式存储 | 分析查询 |
| 全文索引 | 全文搜索 | 文本搜索 |
| 筛选索引 | 部分数据 | 特定条件 |
最佳实践:
- 选择合适的索引类型
- 复合索引注意列顺序
- 使用包含列创建覆盖索引
- 定期维护索引碎片
- 更新统计信息
下一步,让我们学习视图!
最后更新:2026-03-27