1. 首页 > 国产数据库教程 > TiDB教程 > 正文

tidb教程FG086-TiDB大批量数据插入优化

本文档风哥主要介绍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的插入架构:

# 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. 分批次插入
– **方法**:将大批量数据分为多个批次插入
– **优点**:减少内存使用,避免超时
– **缺点**:增加操作步骤

风哥提示:大批量数据插入是TiDB性能优化的重要场景,需要选择合适的插入方法和优化策略。学习交流加群风哥微信: itpux-com

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设计:

# 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**:生成性能报告
– 测试环境
– 测试方法
– 测试结果
– 优化建议

风哥提示:基准测试是优化的基础,通过基准测试可以识别性能瓶颈,验证优化效果。from tidb视频:www.itpux.com

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优化

# 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选项

风哥提示:大批量数据插入优化需要综合考虑硬件、配置、插入方法等多个因素,选择合适的优化策略,才能达到最佳性能。更多视频教程www.fgedu.net.cn

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息