本文档风哥主要介绍TiDB大批量更新删除的优化方法和技巧,包括大批量更新删除相关概念、TiDB更新删除架构、影响更新删除性能的因素、更新删除方法、硬件规划、配置规划、schema设计、优化步骤、调优方法、基准测试流程、实战案例和最佳实践等,风哥教程参考TiDB官方文档性能优化相关内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。更多视频教程www.fgedu.net.cn
Part01-基础概念与理论知识
1.1 大批量更新删除相关概念
大批量更新删除相关的基本概念:
## 1. 批量更新
– **批量更新**:一次更新多条数据的操作
– **更新吞吐量**:单位时间内成功更新的数据量
– **更新延迟**:从更新请求发出到完成的时间
– **批量大小**:每次批量更新的数据条数
## 2. 批量删除
– **批量删除**:一次删除多条数据的操作
– **删除吞吐量**:单位时间内成功删除的数据量
– **删除延迟**:从删除请求发出到完成的时间
– **批量大小**:每次批量删除的数据条数
## 3. 性能指标
– **QPS**:每秒执行的查询数
– **TPS**:每秒执行的事务数
– **更新/删除速率**:每秒更新/删除的数据量(MB/s)
– **平均延迟**:平均更新/删除响应时间
– **P95延迟**:95%的更新/删除请求的响应时间
– **P99延迟**:99%的更新/删除请求的响应时间
## 4. 瓶颈因素
– **网络瓶颈**:网络带宽限制
– **CPU瓶颈**:CPU处理能力限制
– **I/O瓶颈**:磁盘I/O速度限制
– **内存瓶颈**:内存容量限制
– **锁竞争**:并发更新/删除导致的锁竞争
– **事务开销**:事务管理的开销风哥提示:
– **索引维护**:索引更新的开销
– **垃圾回收**:删除操作后的垃圾回收
1.2 TiDB更新删除架构
TiDB的更新删除架构:
## 1. 更新流程
– **客户端**:发送更新请求
– **TiDB服务器**:接收请求,解析SQL,生成执行计划
– **PD**:提供集群元数据
– **TiKV**:存储数据,处理更新操作
– **Raft协议**:保证数据一致性
## 2. 删除流程
– **客户端**:发送删除请求
– **TiDB服务器**:接收请求,解析SQL,生成执行计划
– **PD**:提供集群元数据
– **TiKV**:存储数据,处理删除操作
– **Raft协议**:保证数据一致性
– **垃圾回收**:清理删除的数据
## 3. 更新路径
1. **SQL解析**:TiDB解析SQL语句
2. **执行计划生成**:生成执行计划
3. **事务处理**:处理事务逻辑
4. **数据定位**:定位需要更新的数据
5. **数据修改**:修改数据
6. **Raft复制**:通过Raft协议复制数据到多个TiKV节点
7. **持久化**:将数据持久化到磁盘
8. **响应客户端**:返回更新结果
## 4. 删除路径
1. **SQL解析**:TiDB解析SQL语句
2. **执行计划生成**:生成执行计划
3. **事务处理**:处理事务逻辑
4. **数据定位**:定位需要删除的数据
5. **标记删除**:标记数据为删除状态
6. **Raft复制**:通过Raft协议复制删除操作到多个TiKV节点
7. **持久化**:将删除操作持久化到磁盘
8. **响应客户端**:返回删除结果
9. **垃圾回收**:后台清理删除的数据
## 5. 关键组件
– **TiDB**:SQL层,处理SQL解析和执行
– **PD**:元数据管理,调度和负载均衡
– **TiKV**:存储层,处理数据存储和复制
– **Raft**:分布式一致性协议
– **垃圾回收**:清理删除的数据
## 6. 更新删除特点
– **分布式操作**:数据分布在多个TiKV节点
– **强一致性**:通过Raft协议保证数据一致性
– **水平扩展**:支持通过增加节点扩展更新删除能力
– **事务支持**:支持ACID事务
– **标记删除**:删除操作是标记删除,不是物理删除
1.3 影响更新删除性能的因素
影响TiDB大批量更新删除性能的因素:
- 硬件配置:CPU、内存、磁盘、网络等硬件性能
- 集群规模:TiKV节点数量和分布
- 配置参数:TiDB、PD、TiKV的配置参数
- Schema设计:表结构、索引设计、分区策略
- 更新删除方式:单条更新/删除 vs 批量更新/删除
- 批量大小:每次批量更新/删除的数据条数
- 并发度:同时进行的更新/删除操作数量
- 数据分布:数据是否均匀分布,是否存在热点
- 网络延迟:节点间网络延迟
- 磁盘I/O:磁盘读写速度,I/O调度策略
- 锁竞争:并发操作导致的锁竞争
- 索引维护:索引更新的开销
- 垃圾回收:删除操作后的垃圾回收开销
1.4 更新删除方法
TiDB支持的更新删除方法:
## 1. 单条更新
– **语法**:
“`sql
UPDATE table SET col1 = val1, col2 = val2 WHERE condition;
“`
– **优点**:简单直接
– **缺点**:性能低,适合小批量数据
## 2. 批量更新
– **语法**:
“`sql学习交流加群风哥QQ113257174
UPDATE table SET col1 = val1, col2 = val2 WHERE condition;
“`
– **优点**:减少网络往返,提高性能
– **缺点**:可能导致锁竞争
## 3. 单条删除
– **语法**:
“`sql
DELETE FROM table WHERE condition;
“`
– **优点**:简单直接
– **缺点**:性能低,适合小批量数据
## 4. 批量删除
– **语法**:
“`sql
DELETE FROM table WHERE condition;
“`
– **优点**:减少网络往返,提高性能
– **缺点**:可能导致锁竞争和垃圾回收压力
## 5. 事务批量更新/删除
– **语法**:
“`sql
START TRANSACTION;
UPDATE table SET col1 = val1 WHERE condition;
DELETE FROM table WHERE condition;
COMMIT;
“`
– **优点**:保证数据一致性
– **缺点**:事务开销较大
## 6. 并行更新/删除
– **方法**:多个线程同时执行更新/删除操作
– **优点**:提高更新/删除吞吐量
– **缺点**:可能增加锁竞争
## 7. 分批次更新/删除
– **方法**:将大批量数据分为多个批次更新/删除
– **优点**:减少内存使用,避免超时
– **缺点**:增加操作步骤
## 8. 分区表操作
– **方法**:对分区表进行更新/删除操作
– **优点**:减少锁范围,提高性能
– **缺点**:需要合理设计分区策略
## 9. 使用临时表
– **方法**:使用临时表辅助更新/删除操作
– **优点**:减少锁竞争,提高性能
– **缺点**:增加操作复杂度
Part02-生产环境规划与建议
2.1 硬件规划
大批量更新删除场景下的硬件规划:
## 1. TiDB节点
– **CPU**:8-16核,高主频
– **内存**:32-64GB
– **磁盘**:SSD,200GB以上
– **网络**:万兆网络
## 2. TiKV节点
– **CPU**:16-32核
– **内存**:64-128GB
– **磁盘**:NVMe SSD,1TB以上
– **网络**:万兆网络
## 3. PD节点
– **CPU**:4-8核
– **内存**:16-32GB
– **磁盘**:SSD,100GB以上
– **网络**:万兆网络
## 4. 存储规划
– **TiKV存储**:使用NVMe SSD,提供高I/O性能
– **TiDB存储**:使用SSD,存储日志和临时文件
– **PD存储**:使用SSD,存储元数据
## 5. 网络规划
– **网络拓扑**:使用万兆交换机,确保节点间网络延迟低
– **网络带宽**:确保足够的网络带宽,避免网络瓶颈
– **网络隔离**:将业务网络和管理网络分离
## 6. 硬件推荐
– **TiDB节点**:
– CPU:Intel Xeon Gold 6248或更高
– 内存:64GB DDR4
– 磁盘:2×480GB SSD RAID1
– 网络:10GbE
– **TiKV节点**:
– CPU:Intel Xeon Gold 6248或更高
– 内存:128GB DDR4
– 磁盘:4×1.6TB NVMe SSD
– 网络:10GbE
– **PD节点**:
– CPU:Intel Xeon Gold 6248或更高
– 内存:32GB DDR4
– 磁盘:2×480GB SSD RAID1
– 网络:10GbE
2.2 配置规划
大批量更新删除场景下的配置规划:
## 1. TiDB配置
– **max-connections**:最大连接数,根据并发量设置
“`toml
max-connections = 10000
“`
– **txn-total-size-limit**:事务总大小限制,默认100MB
“`toml
txn-total-size-limit = 209715200 # 200MB
“`
– **stmt-count-limit**:单个语句的最大执行时间(秒)
“`toml
stmt-count-limit = 1000000
“`
– **tmp-storage-size**:临时存储大小
“`toml
tmp-storage-size = -1
“`
– **oom-action**:OOM时的操作
“`toml
oom-action = “cancel”
“`
## 2. TiKV配置
– **storage.block-cache.capacity**:块缓存大小,建议设置为内存的40%
“`toml
[storage.block-cache]
capacity = “64GB”
“`
– **raftstore.capacity**:Raft存储容量
“`toml
[raftstore]
capacity = “1.6TB”
“`
– **raftstore.raft-base-tick-interval**:Raft基础 tick 间隔
“`toml
[raftstore]
raft-base-tick-interval = “200ms”
“`
– **server.grpc-concurrency**:gRPC并发数,建议设置为CPU核心数
“`toml
[server]
grpc-concurrency = 32
“`
– **rocksdb.max-open-files**:RocksDB最大打开文件数
“`toml
[rocksdb]
max-open-files = 8192
“`
– **rocksdb.defaultcf.write-buffer-size**:写入缓冲区大小
“`toml
[rocksdb.defaultcf]
write-buffer-size = “1GB”
max-write-buffer-number = 4
“`
– **storage.gc.enable-compaction-filter**:启用压缩过滤器进行垃圾回收
“`toml
[storage.gc]
enable-compaction-filter = true
“`
– **storage.gc.ratio-threshold**:垃圾回收阈值
“`toml
[storage.gc]
ratio-threshold = 0.5
“`
## 3. PD配置
– **replication.max-replicas**:最大副本数
“`toml
[replication]
max-replicas = 3
“`
– **schedule.leader-schedule-limit**: leader 调度限制
“`toml
[schedule]
leader-schedule-limit = 4
“`
– **schedule.region-schedule-limit**: region 调度限制
“`toml
[schedule]
region-schedule-limit = 2048
“`
– **schedule.replica-schedule-limit**:副本调度限制
“`toml
[schedule]
replica-schedule-limit = 64
“`
## 4. 系统配置
– **文件描述符限制**:
“`bash
echo “* soft nofile 65535” >> /etc/security/limits.conf
echo “* hard nofile 65535” >> /etc/security/limits.conf
“`
– **TCP参数**:
“`bash
echo “net.core.somaxconn = 4096” >> /etc/sysctl.conf
echo “net.ipv4.tcp_max_syn_backlog = 4096” >> /etc/sysctl.conf
echo “net.ipv4.tcp_fin_timeout = 30” >> /etc/sysctl.conf
echo “net.ipv4.tcp_tw_reuse = 1” >> /etc/sysctl.conf
sysctl -p
“`
– **I/O调度**:
“`bash
# 查看当前I/O调度
cat /sys/block/nvme0n1/queue/scheduler
# 设置为none调度器
echo none > /sys/block/nvme0n1/queue/scheduler
“`
2.3 Schema设计
大批量更新删除场景下的Schema设计:
## 1. 表结构设计
– **使用合适的数据类型**:选择合适的数据类型,减少存储空间
“`sql
— 优化前:使用VARCHAR(255)存储IP地址
CREATE TABLE test.table (ip VARCHAR(255));
— 优化后:使用INT UNSIGNED存储IP地址
CREATE TABLE test.table (ip INT UNSIGNED);
“`
– **避免使用TEXT/BLOB**:大字段会影响更新删除性能
“`sql
— 优化前:使用TEXT存储大文本
CREATE TABLE test.table (content TEXT);
— 优化后:使用VARCHAR或分离存储
CREATE TABLE test.table (content VARCHAR(1000));
“`
– **合理设置默认值**:为字段设置合适的默认值
“`sql
CREATE TABLE test.table (
id INT PRIMARY KEY AUTO_INCREMENT,
status INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
“`
## 2. 索引设计
– **减少索引数量**:过多的索引会影响更新删除性能
“`sql
— 优化前:多个索引
CREATE INDEX idx_name ON test.table(name);
CREATE INDEX idx_age ON test.table(age);
CREATE INDEX idx_address ON test.table(address);
— 优化后:只保留必要的索引
CREATE INDEX idx_name_age ON test.table(name, age);
“`
– **使用合适的索引类型**:根据查询模式选择合适的索引类型
“`sql
— 使用前缀索引
CREATE INDEX idx_name ON test.table(name(10));
“`
– **避免在频繁更新的列上创建索引**:减少索引维护开销
“`sql
— 避免在频繁更新的status列上创建索引
— 优化前:
CREATE INDEX idx_status ON test.table(status);
— 优化后:不创建索引或使用其他方案
“`
## 3. 分区设计
– **使用分区表**:将数据分散到多个分区,提高更新删除性能
“`sql
— 按时间分区
CREATE TABLE test.table (
id INT PRIMARY KEY,
created_at DATETIME
) PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026)
);
“`
– **使用哈希分区**:均匀分布数据,避免热点
“`sql
— 按ID哈希分区
CREATE TABLE test.table (
id INT PRIMARY KEY,
name VARCHAR(50)
) PARTITION BY HASH (id) PARTITIONS 8;
“`
– **使用列表分区**:根据业务逻辑分区
“`sql
— 按状态分区
CREATE TABLE test.table (
id INT PRIMARY KEY,
status INT
) PARTITION BY LIST (status) (
PARTITION p_active VALUES IN (1),
PARTITION p_inactive VALUES IN (0),
PARTITION p_other VALUES IN (2, 3, 4)
);
“`
## 4. 主键设计
– **使用自增主键**:避免热点问题
“`sql
— 使用自增主键
CREATE TABLE test.table (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
“`
– **避免使用UUID作为主键**:会导致数据分布不均匀
“`sql
— 优化前:使用UUID
CREATE TABLE test.table (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(50)
);
— 优化后:使用自增主键
CREATE TABLE test.table (
id INT PRIMARY KEY AUTO_INCREMENT,
uuid VARCHAR(36),
name VARCHAR(50)
);
“`
## 5. 其他设计建议
– **使用批量更新/删除**:减少网络往返
“`sql
— 批量更新
UPDATE test.table SET status = 1 WHERE id IN (1, 2, 3, 4, 5);
— 批量删除
DELETE FROM test.table WHERE id IN (1, 2, 3, 4, 5);
“`
– **使用事务批量提交**:减少事务开销
“`sql
— 事务批量提交
START TRANSACTION;
UPDATE test.table SET status = 1 WHERE id = 1;
UPDATE test.table SET status = 1 WHERE id = 2;
DELETE FROM test.table WHERE id = 3;
COMMIT;
“`
– **关闭自动提交**:减少事务开销
“`sql
— 关闭自动提交
SET autocommit = 0;
— 执行批量更新/删除
UPDATE test.table SET status = 1 WHERE id IN (1, 2, 3);
DELETE FROM test.table WHERE id IN (4, 5, 6);
— 手动提交
COMMIT;
“`
Part03-生产环境项目实施方案
3.1 优化步骤
TiDB大批量更新删除性能优化的步骤:
## 1. 准备工作
– **步骤1**:分析数据特点
– 数据量大小
– 数据结构
– 更新删除频率
– 更新删除范围
– **步骤2**:选择更新删除方法
– 批量更新/删除
– 并行更新/删除
– 分批次更新/删除
– 分区表操作
– **步骤3**:优化Schema
– 优化表结构
– 优化索引设计
– 优化分区策略
## 2. 配置优化
– **步骤1**:调整TiDB配置
– 增加max-connections
– 调整txn-total-size-limit
– 优化tmp-storage-size
– **步骤2**:调整TiKV配置
– 增加block-cache.capacity
– 调整write-buffer-size
– 优化gc参数
– **步骤3**:调整系统配置
– 增加文件描述符限制
– 优化TCP参数
– 调整I/O调度
## 3. 更新删除执行
– **步骤1**:执行批量更新/删除
“`sql
— 批量更新
UPDATE test.table SET status = 1 WHERE id BETWEEN 1 AND 1000;
— 批量删除
DELETE FROM test.table WHERE id BETWEEN 1 AND 1000;
“`
– **步骤2**:使用并行更新/删除
“`bash
# 使用多个线程并行更新/删除
python parallel_update_delete.py
“`
– **步骤3**:分批次更新/删除
“`bash
# 分批次更新/删除
python batch_update_delete.py
“`
– **步骤4**:使用分区表操作
“`sql
— 对特定分区进行更新
UPDATE test.table PARTITION (p2023) SET status = 1 WHERE created_at < '2023-01-01';
-- 对特定分区进行删除
DELETE FROM test.table PARTITION (p2023) WHERE created_at < '2023-01-01';
```
## 4. 监控和调优
- **步骤1**:监控更新删除性能
- 更新/删除吞吐量
- 更新/删除延迟
- 资源使用率
- 锁竞争情况
- **步骤2**:分析瓶颈
- 网络瓶颈
- CPU瓶颈
- I/O瓶颈
- 内存瓶颈
- 锁竞争
- 索引维护
- **步骤3**:调整优化策略
- 调整批量大小
- 调整并发度
- 优化更新删除方法
- 调整索引设计
## 5. 验证结果
- **步骤1**:验证数据完整性
```sql
-- 验证更新结果
SELECT COUNT(*) FROM test.table WHERE status = 1;
-- 验证删除结果
SELECT COUNT(*) FROM test.table WHERE id BETWEEN 1 AND 1000;
```
- **步骤2**:验证性能指标
- 更新/删除吞吐量
- 更新/删除延迟
- 资源使用率
- **步骤3**:验证业务正常运行
- 测试查询性能
- 测试其他业务功能
3.2 调优方法
TiDB大批量更新删除的调优方法:
## 1. 批量更新调优
– **调整批量大小**:
– 测试不同批量大小的性能
– 选择最佳批量大小(通常为1000-5000条)
– **使用IN子句**:
“`sql
— 使用IN子句批量更新
UPDATE test.table SET status = 1 WHERE id IN (1, 2, 3, …, 1000);
“`
– **使用范围条件**:
“`sql
— 使用范围条件批量更新
UPDATE test.table SET status = 1 WHERE id BETWEEN 1 AND 1000;
“`
– **使用JOIN更新**:
“`sql
— 使用JOIN更新
UPDATE test.table t1
JOIN test.table2 t2 ON t1.id = t2.id
SET t1.status = t2.status;
“`
## 2. 批量删除调优
– **调整批量大小**:
– 测试不同批量大小的性能
– 选择最佳批量大小(通常为1000-5000条)
– **使用IN子句**:
“`sql
— 使用IN子句批量删除
DELETE FROM test.table WHERE id IN (1, 2, 3, …, 1000);
“`
– **使用范围条件**:
“`sql
— 使用范围条件批量删除
DELETE FROM test.table WHERE id BETWEEN 1 AND 1000;
“`
– **使用TRUNCATE**:
“`sql
— 清空表
TRUNCATE TABLE test.table;
“`
– **使用分区管理**:
“`sql
— 删除整个分区
ALTER TABLE test.table DROP PARTITION p2023;
— 重建分区
ALTER TABLE test.table REORGANIZE PARTITION p2024 INTO (
PARTITION p2024Q1 VALUES LESS THAN (‘2024-04-01’),
PARTITION p2024Q2 VALUES LESS THAN (‘2024-07-01’),
PARTITION p2024Q3 VALUES LESS THAN (‘2024-10-01’),
PARTITION p2024Q4 VALUES LESS THAN (‘2025-01-01′)
);
“`
## 3. 并行更新/删除调优
– **使用多线程**:
“`python
import threading
import pymysql
def update_data(start, end):
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
sql = “UPDATE test.table SET status = 1 WHERE id BETWEEN %s AND %s”
cursor.execute(sql, (start, end))
conn.commit()
cursor.close()
conn.close()
# 创建多个线程
threads = []
batch_size = 10000
total = 100000
for i in range(0, total, batch_size):
t = threading.Thread(target=update_data, args=(i, i + batch_size – 1))
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
“`
– **调整并发度**:
– 根据CPU核心数和网络带宽调整并发度
– 避免过度并发导致性能下降
– **使用连接池**:
“`java
// 配置连接池
HikariConfig config = new HikariConfig();
config.setJdbcUrl(“jdbc:mysql://192.168.1.10:4000/test”);
config.setUsername(“root”);
config.setPassword(“password”);
config.setMaximumPoolSize(50);
config.setMinimumIdle(20);
HikariDataSource dataSource = new HikariDataSource(config);
“`
## 4. 分批次更新/删除调优
– **计算批次大小**:
– 根据数据量和内存大小计算批次大小
– 避免单次批次过大导致内存不足
– **使用游标**:
“`python
import pymysql
def update_in_batches(batch_size):
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
# 获取最大ID
cursor.execute(“SELECT MAX(id) FROM test.table”)
max_id = cursor.fetchone()[0]
# 分批次更新
for i in range(1, max_id + 1, batch_size):
end_id = min(i + batch_size – 1, max_id)
sql = “UPDATE test.table SET status = 1 WHERE id BETWEEN %s AND %s”
cursor.execute(sql, (i, end_id))
conn.commit()
print(f”Updated batch {i} to {end_id}”)
cursor.close()
conn.close()
# 分批次更新,每批10000条
update_in_batches(10000)
“`
– **监控批次执行**:
– 监控每个批次的执行时间
– 调整批次大小以获得最佳性能
## 5. 其他调优方法
– **禁用Binlog**:
“`sql
— 禁用Binlog
SET SESSION sql_log_bin = 0;
“`
– **调整事务隔离级别**:
“`sql
— 使用读已提交隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
“`
– **使用临时表**:
“`sql
— 创建临时表
CREATE TEMPORARY TABLE temp_ids (id INT);
— 插入需要更新/删除的ID
INSERT INTO temp_ids VALUES (1), (2), (3), …, (1000);
— 使用临时表进行更新
UPDATE test.table t
JOIN temp_ids tmp ON t.id = tmp.id
SET t.status = 1;
— 使用临时表进行删除
DELETE t FROM test.table t
JOIN temp_ids tmp ON t.id = tmp.id;
— 删除临时表
DROP TEMPORARY TABLE temp_ids;
“`
– **优化网络传输**:
– 使用压缩传输
– 减少网络往返
– 使用本地连接
– **优化垃圾回收**:
“`sql
— 手动触发垃圾回收
CALL dbms_stats.garbage_collect(‘test’, ‘table’);
“`
3.3 基准测试流程
TiDB大批量更新删除性能的基准测试流程:
## 1. 准备环境
– **步骤1**:部署TiDB集群
“`bash
tiup cluster deploy fgedudb v6.1.0 topology.yaml –user root -p
tiup cluster start fgedudb
“`
– **步骤2**:创建测试数据库和表
“`sql
CREATE DATABASE test;
USE test;
CREATE TABLE sbtest1 (
id INT PRIMARY KEY,
k INT NOT NULL DEFAULT ‘0’,
c CHAR(120) NOT NULL DEFAULT ”,
pad CHAR(60) NOT NULL DEFAULT ”
);
“`
– **步骤3**:导入测试数据
“`bash
# 使用sysbench导入测试数据
sysbench –db-driver=mysql –mysql-host=192.168.1.10 –mysql-port=4000 –mysql-user=root –mysql-password=password –mysql-db=test –table-size=1000000 prepare
“`
## 2. 运行基准测试
– **步骤1**:测试单条更新
“`bash
# 单条更新测试
sysbench –db-driver=mysql –mysql-host=192.168.1.10 –mysql-port=4000 –mysql-user=root –mysql-password=password –mysql-db=test –table-size=1000000 –threads=64 –time=60 oltp_write_only run
“`
– **步骤2**:测试批量更新
“`bash
# 批量更新测试
python batch_update_test.py
“`
– **步骤3**:测试单条删除
“`bash
# 单条删除测试
sysbench –db-driver=mysql –mysql-host=192.168.1.10 –mysql-port=4000 –mysql-user=root –mysql-password=password –mysql-db=test –table-size=1000000 –threads=64 –time=60 oltp_delete run
“`
– **步骤4**:测试批量删除
“`bash
# 批量删除测试
python batch_delete_test.py
“`
– **步骤5**:测试并行更新/删除
“`bash
# 并行更新/删除测试
python parallel_update_delete_test.py
“`
– **步骤6**:测试分区表操作
“`bash
# 分区表操作测试
python partition_table_test.py
“`
## 3. 分析测试结果
– **步骤1**:收集测试结果
– 更新/删除吞吐量
– 更新/删除延迟
– 资源使用率
– 锁竞争情况
– **步骤2**:分析瓶颈
– 网络瓶颈
– CPU瓶颈
– I/O瓶颈
– 内存瓶颈
– 锁竞争
– 索引维护
– **步骤3**:比较不同更新删除方法的性能
– 单条更新/删除 vs 批量更新/删除
– 批量更新/删除 vs 并行更新/删除
– 并行更新/删除 vs 分区表操作
## 4. 优化和验证
– **步骤1**:实施优化方案
– 调整批量大小
– 调整并发度
– 优化更新删除方法
– 调整索引设计
– **步骤2**:重新运行基准测试
“`bash
# 重新运行测试
python batch_update_delete_test.py
“`
– **步骤3**:对比优化前后的结果
– 更新/删除吞吐量提升
– 更新/删除延迟降低
– 资源使用率优化
– 锁竞争减少
## 5. 生成报告
– **步骤1**:整理测试数据
– 不同更新删除方法的性能对比
– 不同批量大小的性能表现
– 不同并发度的性能表现
– 分区表 vs 非分区表的性能对比
– **步骤2**:生成性能报告
– 测试环境
– 测试方法
– 测试结果
– 优化建议
Part04-生产案例与实战讲解
4.1 批量更新优化
## 1. 环境信息
– **TiDB版本**:6.1.0
– **集群规模**:3个TiDB节点,3个TiKV节点,3个PD节点
– **硬件配置**:TiKV节点使用NVMe SSD
– **操作系统**:Oracle Linux 9.3
## 2. 故障现象
– **更新性能低**:单条更新QPS仅为3000
– **网络开销大**:频繁的网络往返
– **CPU使用率高**:TiDB节点CPU使用率达到75%
## 3. 故障分析
– **原因**:应用程序使用单条更新,每个请求都需要网络往返,导致性能瓶颈
– **影响**:无法满足大批量数据更新需求
## 4. 解决方案
– **步骤1**:修改应用程序,使用批量更新
“`java
// 批量更新
String sql = “UPDATE test.table SET status = ? WHERE id IN (“;
StringBuilder ids = new StringBuilder();
for (int i = 0; i < batchSize; i++) {
ids.append("?");
if (i < batchSize - 1) {
ids.append(",");
}
}
sql += ids.toString() + ")";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setInt(1, 1); // status = 1
for (int i = 0; i < batchSize; i++) {
pstmt.setInt(i + 2, idsList.get(i));
}
pstmt.executeUpdate();
```
- **步骤2**:调整批量大小
- 测试不同批量大小的性能
- 选择最佳批量大小(1000条)
- **步骤3**:验证优化效果
```bash
# 运行测试
python batch_update_test.py
```
- **结果**:
- 单条更新QPS:3000
- 批量更新QPS:30000(提升10倍)
- CPU使用率:降低到40%
## 5. 预防措施
- **使用批量更新**:减少网络往返
- **调整批量大小**:根据网络带宽和服务器性能调整
- **监控批量更新性能**:及时发现问题
- **优化连接池**:确保足够的连接数
4.2 批量删除优化
## 1. 环境信息
– **TiDB版本**:6.1.0
– **集群规模**:3个TiDB节点,3个TiKV节点,3个PD节点
– **硬件配置**:TiKV节点使用NVMe SSD
– **操作系统**:Oracle Linux 9.3
## 2. 故障现象
– **删除速度慢**:删除100万条数据需要1小时
– **内存使用率高**:TiDB节点内存使用率达到85%
– **垃圾回收压力大**:删除操作后垃圾回收占用大量资源
## 3. 故障分析
– **原因**:使用单次批量删除,数据量过大,导致内存使用过高和垃圾回收压力大
– **影响**:删除操作超时,系统不稳定
## 4. 解决方案
– **步骤1**:使用分批次删除
“`python
import pymysql
def delete_in_batches(batch_size):
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
# 获取最大ID
cursor.execute(“SELECT MAX(id) FROM test.table”)
max_id = cursor.fetchone()[0]
# 分批次删除
for i in range(1, max_id + 1, batch_size):
end_id = min(i + batch_size – 1, max_id)
sql = “DELETE FROM test.table WHERE id BETWEEN %s AND %s”
cursor.execute(sql, (i, end_id))
conn.commit()
print(f”Deleted batch {i} to {end_id}”)
cursor.close()
conn.close()
# 分批次删除,每批10000条
delete_in_batches(10000)
“`
– **步骤2**:调整批次大小
– 根据内存大小调整批次大小(10000条)
– 避免批次过大导致内存不足
– **步骤3**:优化垃圾回收
“`sql
— 调整垃圾回收参数
SET GLOBAL tidb_gc_life_time = ’10m’;
SET GLOBAL tidb_gc_run_interval = ‘5m’;
“`
– **步骤4**:验证优化效果
“`bash
# 运行测试
python batch_delete_test.py
“`
– **结果**:
– 单次批量删除时间:1小时
– 分批次删除时间:15分钟(提升4倍)
– 内存使用率:稳定在60%
– 垃圾回收压力:明显降低
## 5. 预防措施
– **使用分批次删除**:避免内存不足和垃圾回收压力
– **调整批次大小**:根据内存大小调整
– **优化垃圾回收参数**:减少垃圾回收开销
– **监控删除性能**:及时发现问题
4.3 分区表优化
## 1. 环境信息
– **TiDB版本**:6.1.0
– **集群规模**:3个TiDB节点,3个TiKV节点,3个PD节点
– **硬件配置**:TiKV节点使用NVMe SSD
– **操作系统**:Oracle Linux 9.3
## 2. 故障现象
– **更新删除速度慢**:对大表进行更新删除操作速度慢
– **锁竞争严重**:并发更新删除导致锁竞争
– **资源使用率高**:CPU和I/O使用率达到80%
## 3. 故障分析
– **原因**:使用非分区表,数据集中在一个表中,导致锁竞争和性能瓶颈
– **影响**:更新删除操作超时,业务受到影响
## 4. 解决方案
– **步骤1**:创建分区表
“`sql
— 创建分区表
CREATE TABLE test.table (
id INT PRIMARY KEY,
created_at DATETIME
) PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026)
);
“`
– **步骤2**:导入数据到分区表
“`bash
# 导入数据
mysql -h 192.168.1.10 -P 4000 -u root -p test -e “LOAD DATA LOCAL INFILE ‘/path/to/data.txt’ INTO TABLE test.table;
“`
– **步骤3**:对特定分区进行更新删除操作
“`sql
— 更新特定分区
UPDATE test.table PARTITION (p2023) SET status = 1 WHERE created_at < '2023-06-01';
-- 删除特定分区
DELETE FROM test.table PARTITION (p2023) WHERE created_at < '2023-01-01';
-- 直接删除分区
ALTER TABLE test.table DROP PARTITION p2023;
```
- **步骤4**:验证优化效果
```bash
# 运行测试
python partition_table_test.py
```
- **结果**:
- 非分区表更新时间:30分钟
- 分区表更新时间:5分钟(提升6倍)
- 非分区表删除时间:45分钟
- 分区表删除时间:10分钟(提升4.5倍)
- 锁竞争:明显减少
- 资源使用率:降低到50%
## 5. 预防措施
- **使用分区表**:减少锁范围,提高性能
- **合理设计分区策略**:根据业务需求选择合适的分区方式
- **定期维护分区**:及时清理历史数据
- **监控分区表性能**:及时发现问题
4.4 并发更新删除优化
## 1. 环境信息
– **TiDB版本**:6.1.0
– **集群规模**:3个TiDB节点,3个TiKV节点,3个PD节点
– **硬件配置**:TiKV节点使用NVMe SSD
– **操作系统**:Oracle Linux 9.3
## 2. 故障现象
– **更新删除速度慢**:单线程更新删除100万条数据需要2小时
– **CPU利用率低**:TiDB和TiKV节点CPU利用率仅为30%
– **资源浪费**:硬件资源未充分利用
## 3. 故障分析
– **原因**:使用单线程更新删除,未充分利用硬件资源
– **影响**:更新删除速度慢,无法满足时间要求
## 4. 解决方案
– **步骤1**:使用多线程并行更新删除
“`python
import threading
import pymysql
def update_data(start, end):
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
sql = “UPDATE test.table SET status = 1 WHERE id BETWEEN %s AND %s”
cursor.execute(sql, (start, end))
conn.commit()
cursor.close()
conn.close()
def delete_data(start, end):
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
sql = “DELETE FROM test.table WHERE id BETWEEN %s AND %s”
cursor.execute(sql, (start, end))
conn.commit()
cursor.close()
conn.close()
# 创建16个线程
threads = []
total_rows = 1000000
thread_count = 16
batch_per_thread = total_rows // thread_count
for i in range(thread_count):
start = i * batch_per_thread + 1
end = (i + 1) * batch_per_thread
if i == thread_count – 1:
end = total_rows
# 可以根据需要选择更新或删除
t = threading.Thread(target=update_data, args=(start, end))
# t = threading.Thread(target=delete_data, args=(start, end))
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
“`
– **步骤2**:调整并发度
– 根据CPU核心数调整线程数(16线程)
– 避免过度并发导致性能下降
– **步骤3**:优化连接池
“`java
// 配置连接池
HikariConfig config = new HikariConfig();
config.setJdbcUrl(“jdbc:mysql://192.168.1.10:4000/test”);
config.setUsername(“root”);
config.setPassword(“password”);
config.setMaximumPoolSize(50);
config.setMinimumIdle(20);
HikariDataSource dataSource = new HikariDataSource(config);
“`
– **步骤4**:验证优化效果
“`bash
# 运行测试
python parallel_update_delete_test.py
“`
– **结果**:
– 单线程更新时间:2小时
– 16线程并行更新时间:15分钟(提升8倍)
– 单线程删除时间:2.5小时
– 16线程并行删除时间:20分钟(提升7.5倍)
– CPU利用率:提高到80%
## 5. 预防措施
– **使用多线程并行更新删除**:充分利用硬件资源
– **调整并发度**:根据CPU核心数和网络带宽调整
– **使用连接池**:确保足够的连接数
– **监控并行操作性能**:及时发现问题
Part05-风哥经验总结与分享
5.1 常见问题与解决方案
TiDB大批量更新删除的常见问题与解决方案:
## 1. 内存不足
– **问题**:一次性更新删除过多数据导致内存不足
– **解决**:
– 使用分批次更新删除
– 调整批次大小
– 增加内存容量
## 2. 锁竞争
– **问题**:并发更新删除导致锁竞争,影响性能
– **解决**:
– 优化并发度
– 使用短事务
– 优化索引设计
– 均匀分布数据
– 使用分区表
## 3. 垃圾回收压力
– **问题**:删除操作后垃圾回收占用大量资源
– **解决**:
– 使用分批次删除
– 优化垃圾回收参数
– 定期手动触发垃圾回收
– 使用TRUNCATE替代DELETE
## 4. 网络瓶颈
– **问题**:网络带宽不足,导致更新删除速度慢
– **解决**:
– 使用批量更新删除
– 减少网络往返
– 优化网络配置
– 使用本地连接
## 5. I/O瓶颈
– **问题**:磁盘I/O速度不足,导致更新删除速度慢
– **解决**:
– 使用NVMe SSD
– 优化I/O调度
– 增加TiKV节点
– 合理规划存储
## 6. 事务开销
– **问题**:事务管理开销大,影响更新删除性能
– **解决**:
– 使用批量提交
– 关闭自动提交
– 调整事务隔离级别
– 减少事务大小
## 7. 索引维护
– **问题**:索引维护开销大,影响更新删除性能
– **解决**:
– 减少索引数量
– 优化索引设计
– 避免在频繁更新的列上创建索引
– 延迟创建索引
## 8. 超时错误
– **问题**:更新删除操作超时
– **解决**:
– 分批次更新删除
– 调整超时设置
– 优化更新删除方法
– 减少单次操作数据量
## 9. 数据一致性
– **问题**:更新删除过程中出现数据一致性问题
– **解决**:
– 使用事务
– 验证数据完整性
– 处理并发冲突
– 监控更新删除过程
5.2 最佳实践
TiDB大批量更新删除的最佳实践:
- 选择合适的更新删除方法:根据数据量和场景选择合适的方法
- 使用批量更新删除:减少网络往返,提高性能
- 使用分批次更新删除:避免内存不足和垃圾回收压力
- 使用并行更新删除:充分利用硬件资源
- 使用分区表:减少锁范围,提高性能
- 优化Schema设计:减少索引数量,优化表结构
- 优化配置参数:调整TiDB、TiKV和系统配置
- 监控更新删除性能:及时发现和解决问题
- 验证数据完整性:确保更新删除操作的正确性
- 持续优化:根据业务需求和数据特点持续优化
5.3 优化技巧
TiDB大批量更新删除的实用技巧:
## 1. 更新删除方法选择
– **小批量数据**(<1000条):使用单条更新/删除
- **中批量数据**(1000-10000条):使用批量更新/删除
- **大批量数据**(>10000条):使用分批次更新/删除或并行更新/删除
– **超大批量数据**(>100万条):使用分区表操作或TRUNCATE
## 2. 批量大小调整
– **网络带宽**:带宽越高,批量大小可以越大
– **内存大小**:内存越大,批量大小可以越大
– **服务器性能**:服务器性能越好,批量大小可以越大
– **最佳实践**:通常为1000-5000条
## 3. 并发度调整
– **CPU核心数**:并发度不宜超过CPU核心数
– **网络带宽**:网络带宽越高,并发度可以越大
– **磁盘I/O**:I/O性能越好,并发度可以越大
– **最佳实践**:通常为CPU核心数的1-2倍
## 4. 分区表优化
– **选择合适的分区策略**:根据业务需求选择范围分区、哈希分区或列表分区
– **合理设置分区数量**:分区数量不宜过多,通常为8-16个
– **定期维护分区**:及时清理历史数据,合并或拆分分区
– **使用分区剪枝**:利用分区剪枝提高查询性能
## 5. 索引优化
– **减少索引数量**:只保留必要的索引
– **避免在频繁更新的列上创建索引**:减少索引维护开销
– **使用前缀索引**:减少索引大小
– **延迟创建索引**:先更新删除数据,再创建索引
## 6. 事务优化
– **使用批量提交**:减少事务开销
– **关闭自动提交**:减少事务数量
– **调整事务隔离级别**:使用读已提交隔离级别
– **减少事务大小**:避免长事务
## 7. 硬件优化
– **使用NVMe SSD**:提供更高的I/O性能
– **增加内存**:提高缓存命中率
– **使用万兆网络**:减少网络延迟
– **增加TiKV节点**:提高更新删除能力
## 8. 系统优化
– **调整文件描述符限制**:增加文件描述符限制
– **优化TCP参数**:提高网络性能
– **调整I/O调度**:使用合适的I/O调度器
– **关闭不必要的服务**:减少系统负载
## 9. 监控和调优
– **监控更新删除性能**:实时监控更新删除吞吐量和延迟
– **分析瓶颈**:识别性能瓶颈并解决
– **调整优化策略**:根据实际情况调整优化策略
– **定期测试**:定期进行基准测试,验证优化效果
## 10. 数据处理技巧
– **预处理数据**:在更新删除前预处理数据
– **使用临时表**:先筛选数据到临时表,再进行更新删除
– **使用JOIN操作**:利用JOIN操作优化更新删除
– **处理并发冲突**:合理处理并发更新删除的冲突
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
