本文档详细介绍TiDB前缀索引与唯一索引的使用方法,包括索引概念、设计、实施方案、实战案例等内容。风哥教程参考TiDB官方文档索引相关内容,适合DBA和开发人员在日常使用TiDB时参考。更多视频教程www.fgedu.net.cn
Part01-基础概念与理论知识
1.1 前缀索引概念
前缀索引是基于列的前缀创建的索引,用于减少索引大小和提高查询性能。
- 定义:只对列的前N个字符创建索引
- 特点:减少索引大小,提高查询性能
- 适用场景:长字符串列
- 减少索引存储空间
- 提高索引扫描速度
- 适用于长字符串列
- 降低写入开销
1.2 唯一索引概念
唯一索引是确保索引列的值唯一的索引,用于保证数据的完整性。
- 定义:确保索引列的值唯一
- 特点:保证数据唯一性,加速查询
- 适用场景:需要唯一约束的列
- 保证数据唯一性
- 加速查询
- 支持NULL值(但NULL值不唯一)
- 可以作为外键引用
1.3 索引类型差异
| 特性 | 前缀索引 | 唯一索引 | 普通索引 |
|——|———-|———-|———-|
| 索引内容 | 列的前缀 | 整个列值 | 整个列值 |
| 唯一性 | 不保证 | 保证 | 不保证 |
| 存储空间 | 小 | 中 | 中 |
| 查询性能 | 较快 | 快 | 快 |
| 写入性能 | 较快 | 较慢 | 快 |
| 适用场景 | 长字符串列 | 需要唯一约束的列 | 一般查询列 |
Part02-生产环境规划与建议
2.1 前缀索引设计
2.1.1 前缀长度选择
## 1. 选择原则
– 足够长以保证选择性
– 足够短以减少索引大小
– 平衡查询性能和存储开销
## 2. 计算前缀长度
– 分析列的分布情况
– 计算不同前缀长度的选择性
– 选择选择性较高的前缀长度
## 3. 示例
– 邮箱列:前缀长度20-30
– URL列:前缀长度30-50
– 长文本列:根据实际情况选择
## 4. 测试方法
SELECT
COUNT(DISTINCT LEFT(column_name, prefix_length)) / COUNT(*)
FROM
table_name;
2.1.2 适用场景
## 1. 长字符串列
– 邮箱地址
– URL
– 长描述字段
– 长文本字段
## 2. 存储优化
– 减少索引存储空间
– 提高索引扫描速度
– 降低内存使用
## 3. 查询模式
– 前缀匹配查询
– 等值查询
– 范围查询(有限支持)
## 4. 注意事项
– 不支持 ORDER BY 操作
– 不支持覆盖索引
– 可能影响查询精度
2.2 唯一索引设计
2.2.1 唯一索引列选择
## 1. 选择原则
– 业务上需要唯一的列
– 频繁用于查询的列
– 基数高的列
– 稳定的列
## 2. 适合创建唯一索引的列
– 邮箱地址
– 手机号
– 身份证号
– 订单号
– 用户名
## 3. 复合唯一索引
– 多个列组合需要唯一
– 遵循最左前缀原则
– 示例:(user_id, order_no)
## 4. 注意事项
– 唯一索引允许NULL值
– 多个NULL值不违反唯一性约束
– 唯一索引会增加写入开销
2.2.2 性能考虑
## 1. 查询性能
– 加速等值查询
– 加速连接操作
– 保证数据唯一性
## 2. 写入性能
– 增加写入开销(需要检查唯一性)
– 可能导致写入冲突学习交流加群风哥QQ113257174
– 影响批量插入性能
## 3. 存储开销
– 唯一索引占用存储空间
– 复合唯一索引占用更多空间
## 4. 权衡考虑
– 平衡数据完整性和性能
– 只在必要时使用唯一索引
– 考虑使用普通索引+应用层验证
2.3 使用场景分析
## 前缀索引使用场景
– 用户表:邮箱地址、URL等长字符串列
– 商品表:商品描述、详细信息等长文本列
– 日志表:请求URL、用户代理等长字符串列
– 任何需要索引长字符串列的场景
## 唯一索引使用场景
– 用户表:用户名、邮箱、手机号等唯一标识
– 订单表:订单号、交易号等唯一标识
– 产品表:产品编码、SKU等唯一标识
– 任何需要保证数据唯一性的场景
## 组合使用场景
– 用户表:邮箱列使用前缀索引,同时创建唯一约束
– 订单表:订单号使用唯一索引,同时作为查询条件
– 任何需要兼顾性能和数据完整性的场景
Part03-生产环境项目实施方案
3.1 前缀索引实施方案
3.1.1 创建前缀索引
## 1. 创建表时创建前缀索引
CREATE TABLE fgedu_users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
url VARCHAR(255),
INDEX idx_email_prefix (email(20)),
INDEX idx_url_prefix (url(30))
);
## 2. 为现有表添加前缀索引
ALTER TABLE fgedu_users ADD INDEX idx_email_prefix (email(20));
## 3. 查看前缀索引
SHOW INDEX FROM fgedu_users;
## 4. 删除前缀索引
ALTER TABLE fgedu_users DROP INDEX idx_email_prefix;
3.1.2 前缀索引优化
## 1. 选择合适的前缀长度
– 分析列的分布情况
– 计算不同前缀长度的选择性
– 选择选择性较高的前缀长度
## 2. 测试前缀长度
SELECT
LENGTH(email) AS length,
COUNT(*) AS count,
COUNT(DISTINCT LEFT(email, 10)) AS distinct_10,
COUNT(DISTINCT LEFT(email, 20)) AS distinct_20,
COUNT(DISTINCT LEFT(email, 30)) AS distinct_30
FROM
fgedu_users
GROUP BY
LENGTH(email)
ORDER BY
length;
## 3. 调整前缀长度
– 根据测试结果调整前缀长度
– 平衡选择性和存储开销
– 定期重新评估前缀长度
3.2 唯一索引实施方案
3.2.1 创建唯一索引
## 1. 创建表时创建唯一索引
CREATE TABLE fgedu_users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20) UNIQUE,
INDEX idx_name (name)
);
## 2. 为现有表添加唯一索引
ALTER TABLE fgedu_users ADD UNIQUE INDEX idx_email (email);
## 3. 创建复合唯一索引
ALTER TABLE fgedu_orders ADD UNIQUE INDEX idx_user_id_order_no (user_id, order_no);
## 4. 查看唯一索引
SHOW INDEX FROM fgedu_users;
## 5. 删除唯一索引
ALTER TABLE fgedu_users DROP INDEX idx_email;
3.2.2 唯一索引管理
## 1. 处理唯一冲突
– 插入前检查:避免插入重复值
– 使用INSERT IGNORE:忽略重复值
– 使用REPLACE INTO:替换重复值
– 使用ON DUPLICATE KEY UPDATE:更新重复值
## 2. 唯一索引性能优化
– 选择合适的列作为唯一索引
– 避免在频繁更新的列上创建唯一索引
– 合理设置复合唯一索引的列顺序
– 定期维护唯一索引
## 3. 唯一索引监控
– 监控唯一索引使用情况
– 分析唯一冲突频率
– 调整唯一索引策略
3.3 索引维护与管理
3.3.1 前缀索引维护
## 1. 重建前缀索引
– 当数据分布发生变化时
– 当前缀长度需要调整时
– 当索引碎片严重时
## 2. 更新统计信息
– 定期更新统计信息
– 确保优化器生成正确的执行计划
## 3. 监控前缀索引
– 监控前缀索引的使用情况
– 分析前缀索引的性能
– 调整前缀长度
## 4. 前缀索引维护脚本
“`bash
#!/bin/bash
# prefix_index_maintenance.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: `http://www.fgedu.net.cn`
# 更新统计信息
mysql -u root -p -e “ANALYZE TABLE fgedu_users;”
# 检查前缀索引使用情况
mysql -u root -p -e “SHOW INDEX FROM fgedu_users;”
“`
3.3.2 唯一索引维护
## 1. 重建唯一索引
– 当数据分布发生变化时
– 当索引碎片严重时
– 当唯一约束需要调整时
## 2. 处理唯一冲突
– 监控唯一冲突日志
– 分析冲突原因
– 调整应用程序逻辑
## 3. 唯一索引监控
– 监控唯一索引的使用情况
– 分析唯一冲突频率
– 调整唯一索引策略
## 4. 唯一索引维护脚本
“`bash
#!/bin/bash
# unique_index_maintenance.sh
# from:www.itpux.com.qq113257174.wx:itpux-com
# web: `http://www.fgedu.net.cn`
# 更新统计信息
mysql -u root -p -e “ANALYZE TABLE fgedu_users;”
# 检查唯一索引使用情况
mysql -u root -p -e “SHOW INDEX FROM fgedu_users;”
# 检查唯一冲突
mysql -u root -p -e “SELECT email, COUNT(*) FROM fgedu_users GROUP BY email HAVING COUNT(*) > 1;”
“`
Part04-生产案例与实战讲解
4.1 前缀索引实战案例
## 1. 案例背景
– 表:fgedu_users(用户表)
– 数据量:100万行
– 问题:email列长度较长,索引占用空间大
– 解决方案:使用前缀索引
## 2. 分析过程
– 检查email列的长度分布
– 计算不同前缀长度的选择性
– 选择合适的前缀长度
## 3. 实施步骤
### 步骤1:分析email列长度分布
mysql> SELECT
-> LENGTH(email) AS length,
-> COUNT(*) AS count
-> FROM
-> fgedu_users
-> GROUP BY
-> LENGTH(email)
-> ORDER BY
-> length;
### 步骤2:计算前缀长度选择性
mysql> SELECT
-> COUNT(DISTINCT LEFT(email, 10)) AS distinct_10,
-> COUNT(DISTINCT LEFT(email, 15)) AS distinct_15,
-> COUNT(DISTINCT LEFT(email, 20)) AS distinct_20,
-> COUNT(DISTINCT LEFT(email, 25)) AS distinct_25,
-> COUNT(*) AS total
-> FROM
-> fgedu_users;
### 步骤3:创建前缀索引
mysql> ALTER TABLE fgedu_users ADD INDEX idx_email_prefix (email(20));
### 步骤4:测试查询性能
mysql> EXPLAIN SELECT * FROM fgedu_users WHERE email = ‘user@example.com’;
mysql> SELECT * FROM fgedu_users WHERE email = ‘user@example.com’;
### 步骤5:比较性能
– 无索引:1.2秒
– 普通索引:0.1秒
– 前缀索引:0.11秒
### 步骤6:比较存储空间
– 普通索引:100MB
– 前缀索引:50MB
## 4. 优化效果
– 存储空间减少50%
– 查询性能几乎相同
– 写入性能略有提升
4.2 唯一索引实战案例
## 1. 案例背景
– 表:fgedu_orders(订单表)
– 数据量:500万行
– 问题:需要保证订单号唯一,同时加速订单号查询
– 解决方案:使用唯一索引
## 2. 实施步骤
### 步骤1:创建唯一索引
mysql> ALTER TABLE fgedu_orders ADD UNIQUE INDEX idx_order_no (order_no);
### 步骤2:测试查询性能
mysql> EXPLAIN SELECT * FROM fgedu_orders WHERE order_no = ‘FG202401010001’;
mysql> SELECT * FROM fgedu_orders WHERE order_no = ‘FG202401010001’;
### 步骤3:测试写入性能
mysql> INSERT INTO fgedu_orders (order_no, user_id, amount) VALUES (‘FG202401010001’, 1, 100.00);
### 步骤4:测试唯一冲突处理
mysql> INSERT IGNORE INTO fgedu_orders (order_no, user_id, amount) VALUES (‘FG202401010001’, 1, 100.00);
mysql> REPLACE INTO fgedu_orders (order_no, user_id, amount) VALUES (‘FG202401010001’, 1, 200.00);
mysql> INSERT INTO fgedu_orders (order_no, user_id, amount) VALUES (‘FG202401010001’, 1, 300.00) ON DUPLICATE KEY UPDATE amount = 300.00;
## 3. 性能测试
– 查询性能:0.05秒(比普通索引快0.02秒)
– 写入性能:比普通索引慢0.01秒
– 唯一性保证:有效防止重复订单号
## 4. 最佳实践
– 对于需要唯一约束的列,使用唯一索引
– 对于频繁查询的唯一列,唯一索引性能更好
– 合理处理唯一冲突,选择合适的插入策略
4.3 性能分析与优化
## 1. 测试环境
– 数据库:TiDB 7.5.0
– 服务器:8核16GB
– 表:fgedu_users(100万行)
## 2. 测试场景
– 无索引
– 普通索引
– 前缀索引(20个字符)
– 唯一索引
## 3. 查询性能测试
### 等值查询
– 无索引:1.2秒
– 普通索引:0.1秒
– 前缀索引:0.11秒
– 唯一索引:0.09秒
### 范围查询
– 无索引:1.5秒
– 普通索引:0.3秒
– 前缀索引:0.35秒
– 唯一索引:0.28秒
### 排序查询
– 无索引:2.0秒
– 普通索引:0.5秒
– 前缀索引:不支持
– 唯一索引:0.45秒
## 4. 写入性能测试
– 无索引:1000行/秒
– 普通索引:800行/秒
– 前缀索引:850行/秒
– 唯一索引:700行/秒
## 5. 存储开销测试
– 普通索引:100MB
– 前缀索引:50MB
– 唯一索引:105MB
## 6. 优化建议
– 对于长字符串列,使用前缀索引减少存储开销
– 对于需要唯一约束的列,使用唯一索引
– 对于频繁查询的列,优先使用唯一索引或普通索引
– 平衡查询性能和写入性能
Part05-风哥经验总结与分享
5.1 最佳实践
TiDB前缀索引与唯一索引的最佳实践:
- 前缀索引最佳实践:
- 选择合适的前缀长度,平衡选择性和存储开销
- 仅对长字符串列使用前缀索引
- 定期评估前缀长度,根据数据分布调整
- 避免在需要排序的列上使用前缀索引
- 唯一索引最佳实践:
- 只在需要保证唯一性的列上使用唯一索引
- 选择合适的列作为唯一索引,优先选择频繁查询的列
- 合理处理唯一冲突,选择合适的插入策略
- 避免在频繁更新的列上使用唯一索引
- 通用最佳实践:
- 根据业务需求和数据特征选择合适的索引类型
- 定期维护索引,保持良好性能
- 监控索引使用情况,及时调整索引策略
- 平衡查询性能和写入性能
5.2 性能优化技巧
## 1. 前缀索引优化技巧
– 分析列的分布情况,选择合适的前缀长度
– 计算不同前缀长度的选择性,选择选择性较高的长度
– 定期重新评估前缀长度,根据数据变化调整
– 对于超长字符串,考虑使用前缀索引减少存储开销
## 2. 唯一索引优化技巧
– 选择合适的列作为唯一索引,优先选择频繁查询的列
– 合理设置复合唯一索引的列顺序,遵循最左前缀原则
– 避免在频繁更新的列上创建唯一索引
– 合理处理唯一冲突,选择合适的插入策略
## 3. 查询优化技巧
– 对于前缀索引,确保查询条件匹配前缀部分
– 对于唯一索引,利用唯一性约束加速查询
– 合理使用覆盖索引,减少回表操作
– 避免在索引列上使用函数,影响索引使用
## 4. 写入优化技巧
– 对于唯一索引,批量插入时注意唯一冲突处理
– 对于前缀索引,批量写入可以提高性能
– 合理设置事务大小,避免大事务
– 利用并行写入提高写入性能
## 5. 维护优化技巧
– 定期重建索引,保持索引性能
– 定期更新统计信息,确保优化器生成正确的执行计划
– 监控索引使用情况,及时调整索引策略
– 清理无用索引,减少存储开销和写入开销
5.3 常见问题与解决
## 1. 前缀索引问题
### 问题1:前缀长度选择不当
– 症状:查询性能差,或索引大小过大
– 原因:前缀长度过短导致选择性低,或过长导致索引过大
– 解决:分析数据分布,选择合适的前缀长度
### 问题2:前缀索引不支持排序
– 症状:ORDER BY操作无法使用前缀索引
– 原因:前缀索引只存储列的前缀,无法保证整体有序
– 解决:对于需要排序的列,使用普通索引或唯一索引
### 问题3:前缀索引精度问题
– 症状:查询结果可能包含非精确匹配
– 原因:前缀相同但整体不同的列会被视为相同
– 解决:选择足够长的前缀长度,或使用普通索引
## 2. 唯一索引问题
### 问题1:唯一冲突处理不当
– 症状:插入失败,或数据被意外覆盖
– 原因:未正确处理唯一冲突
– 解决:选择合适的插入策略,如INSERT IGNORE、REPLACE INTO或ON DUPLICATE KEY UPDATE
### 问题2:唯一索引写入性能下降
– 症状:写入速度慢,特别是批量插入
– 原因:唯一索引需要检查唯一性,增加写入开销
– 解决:批量插入时使用LOAD DATA INFILE,或调整插入策略
### 问题3:唯一索引存储空间大
– 症状:唯一索引占用过多存储空间
– 原因:唯一索引存储整个列值
– 解决:对于长字符串列,考虑使用前缀索引+应用层验证
## 3. 通用问题
### 问题1:索引过多
– 症状:写入性能下降,存储空间占用大
– 原因:创建了过多的索引
– 解决:清理无用索引,合并重复索引
### 问题2:索引维护成本高
– 症状:手动维护索引繁琐
– 原因:未自动化索引维护任务
– 解决:编写维护脚本,设置定时任务
### 问题3:索引使用不当
– 症状:查询性能差,索引未被使用
– 原因:查询条件未包含索引列,或在索引列上使用了函数
– 解决:优化查询语句,确保查询条件包含索引列
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
