数据加载是数据库应用开发和测试中经常遇到的需求场景。如果要加载的数据量很大,加载的性能往往会成为瓶颈。最近又遇到了一个典型的数据加载场景,顺手总结一下相关的经验。
综合来看,提高加载速度的办法主要有:
1 优化表结构和定义
1. 表定义中避免采用操作代价较高的数据类型,例如在允许的情况下用 INTEGER 或 DOUBLE 代替 DECIMAL。
2. 延迟进行约束或完整性检查,例如在数据加载之后再创建索引和外码约束等。
3. 针对性的做一些物理参数调优,例如调整数据库页面的大小或充满度。
这一类的优化需要修改数据库设计或专门进行参数调整,可行性受到一定的限制。
2 批量加载数据
1. 如果采用的是 INSERT 语句来加载数据,可以每插入一批记录作为一个事务,通过减少事务数来提高速度。
2. 如果是 MySQL 等允许在 INSERT 的 VALUES 之后出现多行的数据库,可以在每个 INSERT 语句中提供一批数据。
3. 采用服务器端的 PREPARE 和 EXECUTE 语句避免每次都要解析 INSERT 语句,也可以提高加载效率。
这一类的优化集中在数据加载的业务逻辑上,只要允许修改应用程序都可以采用。
3 并行加载数据
1. 应用开多个连接并行地给数据库加载数据。
2. 利用数据库内部实现的功能来并行加载数据。
前者也是修改数据加载的业务逻辑,并行的加载不同的表比较容易实现。如果遇到了个别特别大的表,需要结合业务逻辑并行的加载该表的不同部分。 后者以来数据库内部的并行加载能力,一般来说对数据加载方式会有一些限制,例如采用专门的 API 或 SQL 语法。
4 走特殊执行路径或减少执行路径
1. 不通过数据库引擎,直接产生符合格式的数据库文件。数据库文件的格式通常都比较复杂,不过有些数据库可以直接读取 CSV 等常见的文件格式。
2. 不通过 INSERT 之类的 SQL,采用 LOAD FILE 之类的命令直接加载文件,或直接采用存储引擎的 API。
3. 如果可以确保加载的数据是符合约束的,可以在加载前关掉约束检查,加载之后再打开。
4. 不写或少写日志,例如事务日志、binlog 日志。不过,万一加载过程中宕机了,存在数据损坏的风险。
这一类的优化往往依赖产品的具体特性,可移植性较差。关闭约束检查、不写事务日志等开关又存在导致数据损坏或不一致的风险,非特殊情况都不建议使用。
5 示例
以 TPC-C 数据加载程序为例,通常可以直接采用的优化手段有:
1. 在数据加载之后再创建索引等约束。开源的 SQL 中通常都不带外码约束,可以进一步提高加载速度。
2. 并行加载不同的仓库对应的数据。在 TPC-C 的业务模型中,不同仓库的数据是可以独立加载的。
3. 并行加载不同的表的数据。TPC-C 的表可以分为几组互不相关的集合,并行进行加载。
4. 采用“批量加载数据”一节中的各种方法实现数据加载程序。