本文档风哥主要介绍TiDB大批量数据插入的优化方法和技巧,包括大批量数据插入相关概念、TiDB插入架构、影响插入性能的因素、插入方法、硬件规划、配置规划、schema设计、优化步骤、调优方法、基准测试流程、实战案例和最佳实践等,风哥教程参考TiDB官方文档性能优化相关内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。更多视频教程www.fgedu.net.cn
Part01-基础概念与理论知识
1.1 大批量数据插入相关概念
大批量数据插入相关的基本概念:
## 1. 批量插入
– **批量插入**:一次插入多条数据的操作
– **插入吞吐量**:单位时间内成功插入的数据量
– **插入延迟**:从插入请求发出到完成的时间
– **批量大小**:每次批量插入的数据条数
## 2. 插入类型
– **单条插入**:每次插入一条数据
– **批量插入**:一次插入多条数据
– **事务批量插入**:在事务中执行的批量插入
– **非事务批量插入**:不在事务中执行的批量插入
– **LOAD DATA**:使用LOAD DATA语句导入数据
## 3. 性能指标
– **QPS**:每秒执行的查询数
– **TPS**:每秒执行的事务数
– **插入速率**:每秒插入的数据量(MB/s)
– **平均延迟**:平均插入响应时间
– **P95延迟**:95%的插入请求的响应时间
– **P99延迟**:99%的插入请求的响应时间
## 4. 瓶颈因素
– **网络瓶颈**:网络带宽限制
– **CPU瓶颈**:CPU处理能力限制
– **I/O瓶颈**:磁盘I/O速度限制
– **内存瓶颈**:内存容量限制
– **锁竞争**:并发插入导致的锁竞争风哥提示:
– **事务开销**:事务管理的开销
1.2 TiDB插入架构
TiDB的插入架构:
## 1. 插入流程
– **客户端**:发送插入请求
– **TiDB服务器**:接收请求,解析SQL,生成执行计划
– **PD**:提供集群元数据,分配全局ID
– **TiKV**:存储数据,处理插入操作
– **Raft协议**:保证数据一致性
## 2. 插入路径
1. **SQL解析**:TiDB解析SQL语句
2. **执行计划生成**:生成执行计划
3. **事务处理**:处理事务逻辑
4. **数据编码**:将数据编码为Key-Value格式
5. **Raft复制**:通过Raft协议复制数据到多个TiKV节点
6. **持久化**:将数据持久化到磁盘
7. **响应客户端**:返回插入结果
## 3. 关键组件
– **TiDB**:SQL层,处理SQL解析和执行
– **PD**:元数据管理,调度和负载均衡
– **TiKV**:存储层,处理数据存储和复制
– **Raft**:分布式一致性协议
## 4. 插入特点
– **分布式插入**:数据分布在多个TiKV节点
– **强一致性**:通过Raft协议保证数据一致性
– **水平扩展**:支持通过增加节点扩展插入能力
– **事务支持**:支持ACID事务
1.3 影响插入性能的因素
影响TiDB大批量数据插入性能的因素:
- 硬件配置:CPU、内存、磁盘、网络等硬件性能
- 集群规模:TiKV节点数量和分布
- 配置参数:TiDB、PD、TiKV的配置参数
- Schema设计:表结构、索引设计、分区策略
- 插入方式:单条插入 vs 批量插入,事务插入 vs 非事务插入
- 批量大小:每次批量插入的数据条数
- 并发度:同时进行的插入操作数量
- 数据分布:数据是否均匀分布,是否存在热点
- 网络延迟:节点间网络延迟
- 磁盘I/O:磁盘读写速度,I/O调度策略
1.4 插入方法
TiDB支持的插入方法:
## 1. 单条插入
– **语法**:
“`sql
INSERT INTO table (col1, col2, …) VALUES (val1, val2, …);
“`
– **优点**:简单直接
– **缺点**:性能低,适合小批量数据
## 2. 批量插入
– **语法**:
“`sql
INSERT INTO table (col1, col2, …) VALUES (val1, val2, …), (val1, val2, …), …;
“`
– **优点**:减少网络往返,提高性能
– **缺点**:SQL语句长度限制
## 3. LOAD DATA
– **语法**:
“`sql
LOAD DATA INFILE ‘file.txt’ INTO TABLE table;
“`
– **优点**:高性能,适合大批量数据
– **缺点**:需要文件访问权限
## 4. 事务批量插入
– **语法**:
“`sql
START TRANSACTION;
INSERT INTO table (col1, col2, …) VALUES (val1, val2, …), …;
COMMIT;
“`
– **优点**:保证数据一致性
– **缺点**:事务开销较大
## 5. 并行插入
– **方法**:多个线程同时执行插入操作
– **优点**:提高插入吞吐量学习交流加群风哥QQ113257174
– **缺点**:可能增加锁竞争
## 6. 分批次插入
– **方法**:将大批量数据分为多个批次插入
– **优点**:减少内存使用,避免超时
– **缺点**:增加操作步骤
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
“`
## 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
— 步骤1:创建表时不创建索引
CREATE TABLE test.table (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT
);
— 步骤2:插入数据
INSERT INTO test.table (id, name, age) VALUES (1, ‘test1’, 20), (2, ‘test2’, 30), …;
— 步骤3:创建索引
CREATE INDEX idx_name ON test.table(name);
“`
## 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;
“`
## 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
— 批量插入
INSERT INTO test.table (name, age) VALUES (‘test1’, 20), (‘test2’, 30), (‘test3’, 40);
“`
– **使用事务批量提交**:减少事务开销
“`sql
— 事务批量提交
START TRANSACTION;
INSERT INTO test.table (name) VALUES (‘test1’);
INSERT INTO test.table (name) VALUES (‘test2’);
INSERT INTO test.table (name) VALUES (‘test3’);
COMMIT;
“`
– **关闭自动提交**:减少事务开销
“`sql
— 关闭自动提交
SET autocommit = 0;
— 执行批量插入
INSERT INTO test.table (name) VALUES (‘test1’), (‘test2’), (‘test3’);
— 手动提交
COMMIT;
“`
Part03-生产环境项目实施方案
3.1 优化步骤
TiDB大批量数据插入性能优化的步骤:
## 1. 准备工作
– **步骤1**:分析数据特点
– 数据量大小
– 数据结构
– 插入频率
– **步骤2**:选择插入方法
– 批量插入
– LOAD DATA
– 并行插入
– 分批次插入
– **步骤3**:优化Schema
– 优化表结构
– 优化索引设计
– 优化分区策略
## 2. 配置优化
– **步骤1**:调整TiDB配置
– 增加max-connections
– 调整txn-total-size-limit
– 优化tmp-storage-size
– **步骤2**:调整TiKV配置
– 增加block-cache.capacity
– 调整write-buffer-size
– 优化grpc-concurrency
– **步骤3**:调整系统配置
– 增加文件描述符限制
– 优化TCP参数
– 调整I/O调度
## 3. 插入执行
– **步骤1**:执行批量插入
“`sql
— 批量插入
INSERT INTO test.table (name, age) VALUES (‘test1’, 20), (‘test2’, 30), …, (‘test1000’, 40);
“`
– **步骤2**:使用LOAD DATA
“`sql
— LOAD DATA
LOAD DATA INFILE ‘/path/to/data.txt’ INTO TABLE test.table;
“`
– **步骤3**:并行插入
“`bash
# 使用多个线程并行插入
python parallel_insert.py
“`
– **步骤4**:分批次插入
“`bash
# 分批次插入
python batch_insert.py
“`
## 4. 监控和调优
– **步骤1**:监控插入性能
– 插入吞吐量
– 插入延迟
– 资源使用率
– **步骤2**:分析瓶颈
– 网络瓶颈
– CPU瓶颈
– I/O瓶颈
– 内存瓶颈
– **步骤3**:调整优化策略
– 调整批量大小
– 调整并发度
– 优化插入方法
## 5. 验证结果
– **步骤1**:验证数据完整性
“`sql
— 验证数据条数
SELECT COUNT(*) FROM test.table;
“`
– **步骤2**:验证性能指标
– 插入吞吐量
– 插入延迟
– 资源使用率
– **步骤3**:验证业务正常运行
– 测试查询性能
– 测试其他业务功能
3.2 调优方法
TiDB大批量数据插入的调优方法:
## 1. 批量插入调优
– **调整批量大小**:
– 测试不同批量大小的性能
– 选择最佳批量大小(通常为1000-5000条)
– **使用参数化查询**:
“`java
// 使用参数化查询
String sql = “INSERT INTO test.table (name, age) VALUES (?, ?)”;
PreparedStatement pstmt = connection.prepareStatement(sql);
for (int i = 0; i < batchSize; i++) {
pstmt.setString(1, "test" + i);
pstmt.setInt(2, 20 + i % 30);
pstmt.addBatch();
}
pstmt.executeBatch();
```
- **关闭自动提交**:
```java
// 关闭自动提交
connection.setAutoCommit(false);
try {
// 执行批量插入
pstmt.executeBatch();
// 手动提交
connection.commit();
} catch (SQLException e) {
connection.rollback();
e.printStackTrace();
} finally {
connection.setAutoCommit(true);
}
```
## 2. LOAD DATA调优
- **使用LOCAL选项**:
```sql
-- 使用LOCAL选项
LOAD DATA LOCAL INFILE '/path/to/data.txt' INTO TABLE test.table;
```
- **调整字段分隔符**:
```sql
-- 调整字段分隔符
LOAD DATA INFILE '/path/to/data.txt' INTO TABLE test.table FIELDS TERMINATED BY ',';
```
- **调整行分隔符**:
```sql
-- 调整行分隔符
LOAD DATA INFILE '/path/to/data.txt' INTO TABLE test.table LINES TERMINATED BY '\n';
```
- **使用IGNORE选项**:
```sql
-- 忽略重复键
LOAD DATA INFILE '/path/to/data.txt' INTO TABLE test.table IGNORE;
```
## 3. 并行插入调优
- **使用多线程**:
```python
import threading
import pymysql
def insert_data(start, end):
conn = pymysql.connect(host='192.168.1.10', port=4000, user='root', password='password', db='test')
cursor = conn.cursor()
for i in range(start, end):
sql = "INSERT INTO test.table (name) VALUES (%s)"
cursor.execute(sql, ('test' + str(i),))
conn.commit()
cursor.close()
conn.close()
# 创建多个线程
threads = []
batch_size = 10000
total = 100000
for i in range(0, total, batch_size):
t = threading.Thread(target=insert_data, args=(i, i + batch_size))
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 read_data(file_path, batch_size):
data = []
with open(file_path, 'r') as f:
for line in f:
data.append(line.strip().split(','))
if len(data) >= batch_size:
yield data
data = []
if data:
yield data
# 分批次插入
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
batch_size = 1000
for batch in read_data(‘/path/to/data.txt’, batch_size):
sql = “INSERT INTO test.table (name, age) VALUES (%s, %s)”
cursor.executemany(sql, batch)
conn.commit()
cursor.close()
conn.close()
“`
– **监控批次执行**:
– 监控每个批次的执行时间
– 调整批次大小以获得最佳性能
## 5. 其他调优方法
– **禁用Binlog**:
“`sql
— 禁用Binlog
SET SESSION sql_log_bin = 0;
“`
– **调整事务隔离级别**:
“`sql
— 使用读已提交隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
“`
– **使用临时表**:
“`sql
— 创建临时表
CREATE TEMPORARY TABLE temp_table LIKE test.table;
— 插入数据到临时表
INSERT INTO temp_table (name, age) VALUES (‘test1’, 20), (‘test2’, 30), …;
— 将数据插入到目标表
INSERT INTO test.table SELECT * FROM temp_table;
— 删除临时表
DROP TEMPORARY TABLE temp_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 ”
);
“`
## 2. 准备测试数据
– **步骤1**:生成测试数据
“`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**:导出测试数据
“`bash
# 导出测试数据
mysqldump -h 192.168.1.10 -P 4000 -u root -p test sbtest1 > sbtest1.sql
“`
## 3. 运行基准测试
– **步骤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_insert_test.py
“`
– **步骤3**:测试LOAD DATA
“`bash
# LOAD DATA测试
time mysql -h 192.168.1.10 -P 4000 -u root -p test -e “LOAD DATA INFILE ‘sbtest1.txt’ INTO TABLE sbtest1;
“`
– **步骤4**:测试并行插入
“`bash
# 并行插入测试
python parallel_insert_test.py
“`
## 4. 分析测试结果
– **步骤1**:收集测试结果
– 插入吞吐量
– 插入延迟
– 资源使用率
– **步骤2**:分析瓶颈
– 网络瓶颈
– CPU瓶颈
– I/O瓶颈
– 内存瓶颈
– **步骤3**:比较不同插入方法的性能
– 单条插入 vs 批量插入
– 批量插入 vs LOAD DATA
– LOAD DATA vs 并行插入
## 5. 优化和验证
– **步骤1**:实施优化方案
– 调整批量大小
– 调整并发度
– 优化插入方法
– **步骤2**:重新运行基准测试
“`bash
# 重新运行测试
python batch_insert_test.py
“`
– **步骤3**:对比优化前后的结果
– 插入吞吐量提升
– 插入延迟降低
– 资源使用率优化
## 6. 生成报告
– **步骤1**:整理测试数据
– 不同插入方法的性能对比
– 不同批量大小的性能表现
– 不同并发度的性能表现
– **步骤2**:生成性能报告
– 测试环境
– 测试方法
– 测试结果
– 优化建议
Part04-生产案例与实战讲解
4.1 批量插入优化
## 1. 环境信息
– **TiDB版本**:6.1.0
– **集群规模**:3个TiDB节点,3个TiKV节点,3个PD节点
– **硬件配置**:TiKV节点使用NVMe SSD
– **操作系统**:Oracle Linux 9.3
## 2. 故障现象
– **插入性能低**:单条插入QPS仅为5000
– **网络开销大**:频繁的网络往返
– **CPU使用率高**:TiDB节点CPU使用率达到80%
## 3. 故障分析
– **原因**:应用程序使用单条插入,每个请求都需要网络往返,导致性能瓶颈
– **影响**:无法满足大批量数据插入需求
## 4. 解决方案
– **步骤1**:修改应用程序,使用批量插入
“`java
// 批量插入
String sql = “INSERT INTO test.table (name, age) VALUES (?, ?)”;
PreparedStatement pstmt = connection.prepareStatement(sql);
int batchSize = 1000;
for (int i = 0; i < totalRows; i++) {
pstmt.setString(1, "test" + i);
pstmt.setInt(2, 20 + i % 30);
pstmt.addBatch();
if ((i + 1) % batchSize == 0) {
pstmt.executeBatch();
pstmt.clearBatch();
}
}
// 执行剩余批次
if (totalRows % batchSize != 0) {
pstmt.executeBatch();
}
```
- **步骤2**:调整批量大小
- 测试不同批量大小的性能
- 选择最佳批量大小(1000条)
- **步骤3**:验证优化效果
```bash
# 运行测试
python batch_insert_test.py
```
- **结果**:
- 单条插入QPS:5000
- 批量插入QPS:50000(提升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. 故障现象
– **插入速度慢**:单线程插入1000万条数据需要2小时
– **CPU利用率低**:TiDB和TiKV节点CPU利用率仅为30%
– **资源浪费**:硬件资源未充分利用
## 3. 故障分析
– **原因**:使用单线程插入,未充分利用硬件资源
– **影响**:插入速度慢,无法满足时间要求
## 4. 解决方案
– **步骤1**:使用多线程并行插入
“`python
import threading
import pymysql
def insert_data(start, end):
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
batch_size = 1000
data = []
for i in range(start, end):
data.append((‘test’ + str(i), 20 + i % 30))
if len(data) >= batch_size:
sql = “INSERT INTO test.table (name, age) VALUES (%s, %s)”
cursor.executemany(sql, data)
data = []
if data:
sql = “INSERT INTO test.table (name, age) VALUES (%s, %s)”
cursor.executemany(sql, data)
conn.commit()
cursor.close()
conn.close()
# 创建16个线程
threads = []
total_rows = 10000000
thread_count = 16
batch_per_thread = total_rows // thread_count
for i in range(thread_count):
start = i * batch_per_thread
end = (i + 1) * batch_per_thread
if i == thread_count – 1:
end = total_rows
t = threading.Thread(target=insert_data, args=(start, end))
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
“`
– **步骤2**:调整并发度
– 根据CPU核心数调整线程数(16线程)
– 避免过度并发导致性能下降
– **步骤3**:验证优化效果
“`bash
# 运行测试
python parallel_insert_test.py
“`
– **结果**:
– 单线程插入时间:2小时
– 16线程并行插入时间:15分钟(提升8倍)
– CPU利用率:提高到80%
## 5. 预防措施
– **使用多线程并行插入**:充分利用硬件资源
– **调整并发度**:根据CPU核心数和网络带宽调整
– **监控并行插入性能**:及时发现问题
– **使用连接池**:确保足够的连接数
4.3 LOAD DATA优化
## 1. 环境信息
– **TiDB版本**:6.1.0
– **集群规模**:3个TiDB节点,3个TiKV节点,3个PD节点
– **硬件配置**:TiKV节点使用NVMe SSD
– **操作系统**:Oracle Linux 9.3
## 2. 故障现象
– **插入速度慢**:使用批量插入导入1000万条数据需要30分钟
– **网络开销大**:大量的网络传输
– **CPU使用率高**:TiDB节点CPU使用率达到90%
## 3. 故障分析
– **原因**:使用批量插入,需要解析大量SQL语句,导致性能瓶颈
– **影响**:插入速度慢,无法满足时间要求
## 4. 解决方案
– **步骤1**:使用LOAD DATA导入数据
“`bash
# 准备数据文件
# 数据格式:id,name,age
# 1,test1,20
# 2,test2,30
# …
# 使用LOAD DATA导入
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 FIELDS TERMINATED BY ‘,’ LINES TERMINATED BY ‘\n’;”
“`
– **步骤2**:优化LOAD DATA参数
“`sql
— 禁用Binlog
SET SESSION sql_log_bin = 0;
— 使用LOCAL选项
LOAD DATA LOCAL INFILE ‘/path/to/data.txt’ INTO TABLE test.table;
“`
– **步骤3**:验证优化效果
“`bash
# 运行测试
time 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;”
“`
– **结果**:
– 批量插入时间:30分钟
– LOAD DATA导入时间:5分钟(提升6倍)
– CPU使用率:降低到50%
## 5. 预防措施
– **使用LOAD DATA**:适合大批量数据导入
– **优化LOAD DATA参数**:使用LOCAL选项,调整分隔符
– **监控LOAD DATA性能**:及时发现问题
– **准备好数据文件**:确保数据文件格式正确
4.4 分批次插入优化
## 1. 环境信息
– **TiDB版本**:6.1.0
– **集群规模**:3个TiDB节点,3个TiKV节点,3个PD节点
– **硬件配置**:TiKV节点使用NVMe SSD
– **操作系统**:Oracle Linux 9.3
## 2. 故障现象
– **内存不足**:一次性插入1000万条数据导致内存不足
– **超时错误**:插入操作超时
– **系统不稳定**:内存使用过高导致系统不稳定
## 3. 故障分析
– **原因**:一次性插入过多数据,导致内存使用过高
– **影响**:插入失败,系统不稳定
## 4. 解决方案
– **步骤1**:使用分批次插入
“`python
import pymysql
def insert_in_batches(file_path, batch_size):
conn = pymysql.connect(host=’192.168.1.10′, port=4000, user=’root’, password=’password’, db=’test’)
cursor = conn.cursor()
with open(file_path, ‘r’) as f:
batch = []
for line in f:
parts = line.strip().split(‘,’)
if len(parts) == 3:
batch.append((parts[0], parts[1], parts[2]))
if len(batch) >= batch_size:
sql = “INSERT INTO test.table (id, name, age) VALUES (%s, %s, %s)”
cursor.executemany(sql, batch)
conn.commit()
batch = []
# 处理剩余数据
if batch:
sql = “INSERT INTO test.table (id, name, age) VALUES (%s, %s, %s)”
cursor.executemany(sql, batch)
conn.commit()
cursor.close()
conn.close()
# 分批次插入,每批10000条
insert_in_batches(‘/path/to/data.txt’, 10000)
“`
– **步骤2**:调整批次大小
– 根据内存大小调整批次大小(10000条)
– 避免批次过大导致内存不足
– **步骤3**:验证优化效果
“`bash
# 运行测试
python batch_insert_in_batches.py
“`
– **结果**:
– 一次性插入:失败(内存不足)
– 分批次插入:成功完成
– 内存使用:稳定在合理范围
## 5. 预防措施
– **使用分批次插入**:避免内存不足
– **调整批次大小**:根据内存大小调整
– **监控内存使用**:及时发现内存问题
– **优化数据处理**:使用游标逐行读取数据
Part05-风哥经验总结与分享
5.1 常见问题与解决方案
TiDB大批量数据插入的常见问题与解决方案:
## 1. 内存不足
– **问题**:一次性插入过多数据导致内存不足
– **解决**:
– 使用分批次插入
– 调整批次大小
– 增加内存容量
## 2. 网络瓶颈
– **问题**:网络带宽不足,导致插入速度慢
– **解决**:
– 使用批量插入
– 使用LOAD DATA
– 优化网络配置
– 使用本地连接
## 3. I/O瓶颈
– **问题**:磁盘I/O速度不足,导致插入速度慢
– **解决**:
– 使用NVMe SSD
– 优化I/O调度
– 增加TiKV节点
– 合理规划存储
## 4. 锁竞争
– **问题**:并发插入导致锁竞争,影响性能
– **解决**:
– 优化并发度
– 使用短事务
– 优化索引设计
– 均匀分布数据
## 5. 事务开销
– **问题**:事务管理开销大,影响插入性能
– **解决**:
– 使用批量提交
– 关闭自动提交
– 调整事务隔离级别
– 减少事务大小
## 6. 索引开销
– **问题**:索引维护开销大,影响插入性能
– **解决**:
– 延迟创建索引
– 减少索引数量
– 优化索引设计
– 使用覆盖索引
## 7. 超时错误
– **问题**:插入操作超时
– **解决**:
– 分批次插入
– 调整超时设置
– 优化插入方法
– 减少单次操作数据量
## 8. 数据一致性
– **问题**:插入过程中出现数据一致性问题
– **解决**:
– 使用事务
– 验证数据完整性
– 处理重复数据
– 监控插入过程
5.2 最佳实践
TiDB大批量数据插入的最佳实践:
- 选择合适的插入方法:根据数据量和场景选择合适的插入方法
- 使用批量插入:减少网络往返,提高性能
- 使用LOAD DATA:适合大批量数据导入
- 使用并行插入:充分利用硬件资源
- 使用分批次插入:避免内存不足和超时
- 优化Schema设计:减少索引数量,优化表结构
- 优化配置参数:调整TiDB、TiKV和系统配置
- 监控插入性能:及时发现和解决问题
- 验证数据完整性:确保插入数据的一致性
- 持续优化:根据业务需求和数据特点持续优化
5.3 优化技巧
TiDB大批量数据插入的实用技巧:
## 1. 插入方法选择
– **小批量数据**(<1000条):使用单条插入或小批量插入
- **中批量数据**(1000-10000条):使用批量插入
- **大批量数据**(>10000条):使用LOAD DATA或并行插入
## 2. 批量大小调整
– **网络带宽**:带宽越高,批量大小可以越大
– **内存大小**:内存越大,批量大小可以越大
– **服务器性能**:服务器性能越好,批量大小可以越大
– **最佳实践**:通常为1000-5000条
## 3. 并行度调整
– **CPU核心数**:并行度不宜超过CPU核心数
– **网络带宽**:网络带宽越高,并行度可以越大
– **磁盘I/O**:I/O性能越好,并行度可以越大
– **最佳实践**:通常为CPU核心数的1-2倍
## 4. LOAD DATA优化
– **使用LOCAL选项**:减少网络传输
– **调整分隔符**:根据数据格式调整
– **禁用Binlog**:减少写入开销
– **使用IGNORE选项**:处理重复数据
## 5. 索引优化
– **延迟创建索引**:先插入数据,再创建索引
– **减少索引数量**:只保留必要的索引
– **优化索引设计**:合理设计复合索引
– **使用覆盖索引**:减少回表操作
## 6. 事务优化
– **使用批量提交**:减少事务开销
– **关闭自动提交**:减少事务数量
– **调整事务隔离级别**:使用读已提交隔离级别
– **减少事务大小**:避免长事务
## 7. 硬件优化
– **使用NVMe SSD**:提供更高的I/O性能
– **增加内存**:提高缓存命中率
– **使用万兆网络**:减少网络延迟
– **增加TiKV节点**:提高写入能力
## 8. 系统优化
– **调整文件描述符限制**:增加文件描述符限制
– **优化TCP参数**:提高网络性能
– **调整I/O调度**:使用合适的I/O调度器
– **关闭不必要的服务**:减少系统负载
## 9. 监控和调优
– **监控插入性能**:实时监控插入吞吐量和延迟
– **分析瓶颈**:识别性能瓶颈并解决
– **调整优化策略**:根据实际情况调整优化策略
– **定期测试**:定期进行基准测试,验证优化效果
## 10. 数据处理技巧
– **预处理数据**:在插入前预处理数据
– **使用压缩**:减少数据传输量
– **使用临时表**:先插入临时表,再导入目标表
– **处理重复数据**:使用IGNORE或REPLACE选项
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
