尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

MySQL LOAD DATA INFILE 批量数据导入:原理、实战与性能调优指南

MySQL LOAD DATA INFILE 批量数据导入:原理、实战与性能调优指南 1. 项目概述为什么LOAD DATA INFILE是数据工程师的“瑞士军刀”在数据处理的日常里我们经常遇到一个场景手头有一份几百万行的CSV或TXT文件需要快速、完整地导入到MySQL数据库里。用程序一行行INSERT那太慢了光是网络I/O和事务开销就让人等得心焦。用图形化工具点点点文件一大就卡死还容易因为编码问题导致乱码。这时候MySQL自带的一个“神器”就该登场了——LOAD DATA INFILE命令。简单来说LOAD DATA INFILE是MySQL提供的一条从服务器本地文本文件高速批量导入数据到数据库表的SQL语句。它的速度有多快在我的实际项目中导入一个包含1000万行、大小约2GB的CSV文件到InnoDB表通过精心调优的LOAD DATA INFILE耗时可以控制在3分钟以内这比传统的INSERT语句快了不止一个数量级。它绕过了SQL解析和网络通信的层层开销直接以接近磁盘I/O极限的速度将数据“灌”入表中是数据迁移、日志分析、报表初始化等场景下的首选方案。然而这把“瑞士军刀”虽然锋利但新手直接上手很容易割伤自己。文件路径权限不对、字符集混乱、字段分隔符错位、主键冲突……任何一个细节没处理好都会导致导入失败或数据错乱。网上能找到的教程往往只给出一个最简单的成功案例对背后复杂的参数和层出不穷的错误语焉不详。这篇文章我就结合自己这些年踩过的坑和填过的坑把LOAD DATA INFILE从核心原理、完整实操到错误排查给你一次讲透。无论你是运维、开发还是数据分析师下次再面对海量数据文件时都能从容地用它搞定。2. 核心原理与前置条件理解“高速”背后的机制在动手之前我们必须先搞清楚LOAD DATA INFILE为什么快以及它运行需要哪些前提条件。知其然更要知其所以然这能帮助我们在遇到问题时快速定位根源。2.1 工作机制绕过SQL层的“数据管道”普通的INSERT INTO table VALUES (...), (...), ...语句即使使用多值插入也需要经过以下步骤客户端将SQL语句通过网络发送到MySQL服务器。服务器端的SQL解析器对语句进行词法、语法分析。优化器生成执行计划。存储引擎如InnoDB开始处理每一行数据检查约束、更新索引、写入事务日志redo log、最终写入数据页。这个过程伴随着大量的事务管理和锁竞争。而LOAD DATA INFILE的工作流程则精简得多文件读取MySQL服务器进程mysqld直接从操作系统文件系统读取指定的数据文件。这意味着文件必须位于MySQL服务器所在的主机上客户端无法直接读取自己本机的文件除非使用LOAD DATA LOCAL INFILE但这引入了安全性和配置问题后面会详述。流式解析服务器按照我们指定的格式如字段分隔符FIELDS TERMINATED BY ,、行分隔符LINES TERMINATED BY \n对文件进行流式解析将文本行拆分成一个个字段值。批量应用解析出的数据会以大批量的方式直接发送给存储引擎。对于InnoDB它会利用其变更缓冲区Change Buffer来优化非唯一二级索引的更新并可能采用一种更高效的方式来处理自增主键的分配和页的填充极大地减少了离散I/O和锁的粒度。这种“直达”的方式避免了SQL解析、网络传输和单行事务的开销是性能提升的关键。2.2 关键前置条件与权限检查不是在任何情况下都能随意使用这个命令的。以下是必须满足的条件请务必在操作前逐一核对FILE权限执行该命令的MySQL用户必须拥有FILE全局权限。这个权限允许MySQL服务器进程读取服务器主机上的文件。-- 查看当前用户权限 SHOW GRANTS FOR CURRENT_USER; -- 或 SHOW GRANTS; -- 授予FILE权限需要GRANT权限的用户执行 GRANT FILE ON *.* TO your_usernameyour_host; FLUSH PRIVILEGES;注意FILE权限是一个高危权限因为它允许用户读取服务器上任何MySQL进程有权限读取的文件。在生产环境中应仅将其授予受信任的、专门用于数据导入的用户并限定其来源主机如importer192.168.1.100。文件路径与权限路径INFILE子句后面跟的文件路径是MySQL服务器所在操作系统上的路径不是客户端机器的路径。例如你的MySQL跑在Linux服务器/data/mysql/目录下那么你的数据文件也必须上传到这个服务器的某个位置比如/tmp/data.csv。操作系统权限运行MySQL服务通常是mysql用户或mysqld进程所属用户必须对该数据文件有读权限对文件所在目录有执行权限。这是最常见的失败原因之一。# 在MySQL服务器上检查 ls -l /tmp/data.csv # 应确保 mysql 用户可读 # 如-rw-r--r-- 1 root root 100M Jul 1 10:00 /tmp/data.csv # 如果属主是root需要更改权限或属主 sudo chown mysql:mysql /tmp/data.csv sudo chmod 644 /tmp/data.csvsecure_file_priv系统变量这是MySQL的一个安全限制。它定义了LOAD DATA INFILE和SELECT ... INTO OUTFILE可以访问的目录。-- 查看当前设置 SHOW VARIABLES LIKE secure_file_priv;如果值为NULL则禁止使用这些语句常见于较新版本的默认安装。如果值为一个目录路径如/var/lib/mysql-files/则只能从该目录导入或导出到该目录。如果值为空字符串则表示不限制安全性较低不推荐。解决方案要么将数据文件移动到secure_file_priv指定的目录下要么在确保安全的前提下在MySQL配置文件如my.cnf中修改该变量并重启服务。[mysqld] secure_file_priv /your/safe/directory/3. 命令语法深度解析与实战参数调优一个完整的LOAD DATA INFILE语句包含多个子句每个子句都控制着导入过程的一个关键环节。下面我们拆解每一个部分。3.1 基础语法框架LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE file_name [REPLACE | IGNORE] INTO TABLE tbl_name [CHARACTER SET charset_name] [FIELDS [TERMINATED BY string] [[OPTIONALLY] ENCLOSED BY char] [ESCAPED BY char] ] [LINES [STARTING BY string] [TERMINATED BY string] ] [IGNORE number {LINES | ROWS}] [(col_name_or_user_var [, col_name_or_user_var] ...)] [SET col_name expr [, col_name expr] ...]3.2 核心子句详解与配置示例3.2.1[LOCAL]关键字本地与服务器文件之辨不加LOCALfile_name是MySQL服务器主机上的路径。这是最高效的模式因为服务器直接磁盘读取。加LOCALfile_name是客户端主机上的路径。文件内容会通过客户端连接传输到服务器再由服务器处理。这带来了便利但也引入了安全风险服务器可能加载客户端上的恶意文件和性能开销。使用LOCAL通常需要额外的客户端库支持和配置且受local_infile系统变量控制。-- 在服务器端启用local_infile如果需要的话 SET GLOBAL local_infile 1;实操心得在可控的内网环境或一次性导入任务中为了方便可以使用LOCAL。但在生产环境或自动化脚本中我强烈建议先将文件上传到服务器指定目录如secure_file_priv目录然后使用不带LOCAL的命令。这样更安全性能也更好。3.2.2[REPLACE | IGNORE]关键字主键/唯一键冲突处理这是数据合并时的关键策略。REPLACE如果导入的数据行与表中现有行的主键或唯一键冲突则删除原有行并插入新行。相当于先DELETE再INSERT。IGNORE如果冲突则静默跳过该行导入不报错继续后续行。两者都不指定默认行为是报错并终止整个导入操作。注意事项REPLACE对于有自增主键的表要小心。如果替换了一行该行的自增ID会被新的ID覆盖可能导致业务逻辑混乱。IGNORE则可能导致数据不完整。最佳实践是在导入前确保源数据主键唯一或先导入到临时表再通过INSERT ... ON DUPLICATE KEY UPDATE ...进行更精细的合并。3.2.3CHARACTER SET字符集设置务必指定与数据文件编码一致的字符集。否则中文等非ASCII字符就会变成乱码。常见的文件编码utf8mb4推荐支持完整Unicode包括emoji、gbk、latin1。如何检查文件编码在Linux下可以用file或enca命令。file -i data.csv # 输出可能为data.csv: text/plain; charsetutf-8-- 在LOAD DATA语句中指定 LOAD DATA INFILE /tmp/data.csv INTO TABLE my_table CHARACTER SET utf8mb4 ...;3.2.4FIELDS和LINES子句定义文件格式这是解析文件的“地图”必须与文件实际格式严丝合缝。1. FIELDS 子句TERMINATED BY字段分隔符。CSV常用,TSVTab分隔常用\t。ENCLOSED BY字段引用符。很多CSV文件会用双引号把字段括起来特别是字段内包含分隔符时。例如Smith, John, 28, Engineer。OPTIONALLY可选修饰符用在ENCLOSED BY前。表示只有被引用符括起来的字段才按引用符处理否则忽略。对于混合格式有的字段有引号有的没有很实用。ESCAPED BY转义字符。默认是反斜杠\。如果字段值中包含分隔符或引用符本身就需要用它转义如Say \Hello\。2. LINES 子句TERMINATED BY行分隔符。在Linux/Unix上是\n在Windows上是\r\n在旧Mac上是\r。这是最常见的错误来源之一。如果文件是在Windows生成但导入到Linux服务器不指定\r\n会导致最后一行解析错误或整行被当作一个字段。STARTING BY行起始符。较少用可用于跳过每行开头固定的字符如日志时间戳。格式配置示例假设有一个复杂的CSV文件data.csv内容如下id,name,description,salary 1,Doe, John,He said: \Hello World!\,5000 2,Smith Jane,Software Engineer,6000对应的LOAD DATA语句应为LOAD DATA INFILE /tmp/data.csv INTO TABLE employees CHARACTER SET utf8mb4 FIELDS TERMINATED BY , OPTIONALLY ENCLOSED BY ESCAPED BY \\ -- 注意在SQL字符串中反斜杠需要转义 LINES TERMINATED BY \n IGNORE 1 LINES -- 跳过标题行 (id, name, description, salary);3.2.5IGNORE number LINES跳过文件头部用于跳过标题行Header。例如IGNORE 1 LINES。如果文件有多个注释行就忽略对应的行数。3.2.6 列列表与SET子句数据映射与转换(col_name_or_user_var, ...)指定文件中的字段按顺序对应到表的哪些列。如果省略则默认文件中的字段顺序必须与表定义中的列顺序完全一致。这是一个极易出错的地方特别是表结构发生过变更时。SET子句可以对导入的数据进行实时计算或转换。LOAD DATA INFILE /tmp/data.txt INTO TABLE orders (order_id, product_name, raw_price) -- 文件只提供这三个字段 SET final_price raw_price * 0.9, -- 打九折 import_time NOW(); -- 记录导入时间4. 完整实战流程从文件准备到导入验证让我们通过一个模拟真实业务的例子走一遍全流程。场景将一份用户行为日志CSV导入到分析库。4.1 步骤一在MySQL服务器上准备数据文件假设我们通过scp或sftp将文件user_logs_20230701.csv上传到了服务器的/var/lib/mysql-files/目录该目录通常是secure_file_priv的默认值。 文件内容预览timestamp,user_id,action,device,extra_info 2023-07-01 08:01:23,1001,login,iPhone 13,{network:4G} 2023-07-01 08:02:45,1002,view_item,Android,{item_id: A123} 2023-07-01 08:05:11,1001,purchase,Windows PC,{amount: 299.00, payment: credit_card}4.2 步骤二在MySQL中创建目标表根据文件内容设计表结构。注意字段类型和长度。CREATE TABLE user_behavior_logs ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 自增主键, log_time datetime NOT NULL COMMENT 行为时间, user_id int(11) NOT NULL COMMENT 用户ID, action varchar(50) NOT NULL COMMENT 行为类型, device varchar(100) DEFAULT NULL COMMENT 设备信息, extra_info_json json DEFAULT NULL COMMENT 额外信息(JSON格式), import_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 导入时间, PRIMARY KEY (id), KEY idx_user_time (user_id,log_time), KEY idx_time (log_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci COMMENT用户行为日志表;设计要点extra_info字段在CSV里是JSON字符串我们直接使用MySQL的JSON数据类型来存储便于后续查询。import_at用于记录数据导入时间这是一个好习惯。4.3 步骤三执行LOAD DATA INFILE命令现在组装我们的命令。注意文件中的extra_info是JSON字符串我们需要用SET子句将其转换为JSON类型。-- 首先确认文件权限和路径 -- 假设 secure_file_priv 就是 /var/lib/mysql-files/ LOAD DATA INFILE /var/lib/mysql-files/user_logs_20230701.csv INTO TABLE user_behavior_logs CHARACTER SET utf8mb4 FIELDS TERMINATED BY , OPTIONALLY ENCLOSED BY ESCAPED BY \\ LINES TERMINATED BY \n IGNORE 1 LINES -- 跳过标题行 (log_time, user_id, action, device, extra_info_json) -- 用用户变量临时接收 SET log_time STR_TO_DATE(log_time, %Y-%m-%d %H:%i:%s), -- 转换时间格式 user_id user_id, action action, device NULLIF(device, ), -- 如果device字段为空字符串则存为NULL extra_info_json JSON_UNQUOTE(extra_info_json), -- 去除JSON字符串两端的引号使其成为有效的JSON import_at CURRENT_TIMESTAMP; -- 使用SET子句中的值会覆盖列的DEFAULT值关键点解析用户变量var在列列表中我们可以使用用户变量来临时存储从文件读取的原始值。这给了我们极大的灵活性可以在SET子句中对这些变量进行加工。STR_TO_DATE文件中的时间戳是字符串需要用这个函数按指定格式解析成MySQL的DATETIME类型。NULLIF一个实用的函数如果第一个参数等于第二个参数则返回NULL。这里用于处理可能存在的空设备字段。JSON_UNQUOTE因为文件中的JSON被双引号括着读进来是一个带引号的字符串如{\network\:\4G\}。JSON_UNQUOTE去掉外层的引号使其变成{network:4G}这样才能被正确存入JSON列。4.4 步骤四验证导入结果执行完成后不要假设一切顺利务必进行检查。-- 1. 检查导入行数 SELECT ROW_COUNT(); -- 上一条语句影响的行数 SELECT COUNT(*) FROM user_behavior_logs; -- 表总行数 -- 2. 随机抽查几行数据看格式是否正确 SELECT * FROM user_behavior_logs LIMIT 3\G -- 使用\G垂直输出便于查看JSON字段 -- 检查log_time是否为正确的DATETIMEextra_info_json是否能被JSON函数解析 SELECT id, JSON_EXTRACT(extra_info_json, $.network) FROM user_behavior_logs WHERE action login; -- 3. 检查数据完整性对比源文件行数 -- 可以在导入前用 wc -l 命令计算文件行数减去标题行5. 高频错误代码与排查指南大全即使准备得再充分错误也难免会发生。下面是我整理的最常见的错误、原因及解决方法。5.1 错误代码 1290 (HY000): The MySQL server is running with the --secure-file-priv option问题描述执行命令时直接报此错误无法继续。原因分析这是最经典的错误。MySQL的secure_file_priv变量限制了文件导入/导出的目录。解决方案查询当前设置SHOW VARIABLES LIKE secure_file_priv;方法A推荐将你的数据文件移动到该变量指定的目录下。例如如果值是/var/lib/mysql-files/就把文件拷到那里。方法B修改配置需重启如果需要永久修改编辑MySQL配置文件如/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf在[mysqld]段添加或修改[mysqld] secure_file_priv /your/desired/directory/然后重启MySQL服务sudo systemctl restart mysql。注意将目录设置为空字符串可以禁用此限制但有安全风险不推荐生产环境使用。5.2 错误代码 13 (HY000): Cant get stat of /path/to/file.csv (Errcode: 13 - Permission denied)问题描述文件明明存在但MySQL说权限不够。原因分析运行MySQL服务的系统用户通常是mysql对目标文件或文件所在路径的父目录没有足够的读取或执行权限。排查与解决确认MySQL服务进程的用户ps aux | grep mysqld。通常是mysql。检查文件及其父目录的权限ls -la /path/to/ ls -la /path/to/file.csv确保mysql用户至少对文件有读(r)权限对文件所在的所有上级目录都有执行(x)权限。# 常用修正命令 sudo chown mysql:mysql /path/to/file.csv # 更改文件属主 sudo chmod 644 /path/to/file.csv # 设置文件权限为rw-r--r-- sudo chmod x /path/to/ # 确保目录对mysql用户有执行权踩坑记录有一次在CentOS上文件放在/tmp下但/tmp目录的权限是drwxrwxrwt最后一位t是粘滞位虽然mysql用户有执行权但某些安全配置下仍可能出问题。最稳妥的办法还是使用MySQL专用的目录如secure_file_priv指定的目录。5.3 错误代码 2 (HY000): File /path/to/file.csv not found (Errcode: 2)问题描述找不到文件。原因分析路径拼写错误或文件确实不存在于该路径。使用了相对路径。LOAD DATA INFILE通常需要绝对路径。如果使用了LOCAL关键字文件是在客户端机器上但客户端没有找到该文件。解决方案使用绝对路径。在服务器上使用ls -l命令确认文件是否存在且路径正确。对于LOCAL确保客户端程序如mysql命令行客户端有权限读取该文件。5.4 错误代码 29 (HY000): File /path/to/file.csv not found (Errcode: 29 - Illegal seek)问题描述这个错误比较诡异文件存在权限也对但报“非法定位”。原因分析文件可能是一个符号链接symlink而MySQL出于安全考虑默认不允许跟随符号链接。解决方案检查文件是否为符号链接ls -l /path/to/file.csv如果第一个字符是l那就是链接。要么使用链接指向的实际文件路径要么在MySQL配置中启用--symbolic-links选项不推荐有安全风险。5.5 错误代码 1062 (23000): Duplicate entry XXX for key PRIMARY问题描述导入过程中断提示主键重复。原因分析要导入的数据中包含与表中现有数据重复的主键或唯一键值并且你没有使用IGNORE或REPLACE选项。解决方案方案一忽略重复在命令中加入IGNORE关键字。重复的行会被跳过但会记录警告。执行后可以用SHOW WARNINGS;查看跳过了多少行。方案二替换重复在命令中加入REPLACE关键字。旧行会被删除新行插入。注意自增ID的变化和可能的外键约束。方案三精细合并这是最推荐的做法。先将数据导入到一个临时表CREATE TEMPORARY TABLE tmp LIKE target_table;然后在临时表和目标表之间使用INSERT ... ON DUPLICATE KEY UPDATE ...语句可以自由决定冲突时更新哪些字段。-- 先导入到临时表 LOAD DATA INFILE ... INTO TEMPORARY TABLE tmp ...; -- 再合并到目标表 INSERT INTO target_table SELECT * FROM tmp ON DUPLICATE KEY UPDATE some_column VALUES(some_column), another_column VALUES(another_column);5.6 错误代码 1366 (HY000): Incorrect string value: \xE4\xB8\xAD\xE6\x96\x87 for column name at row 1问题描述中文字符导入后变成乱码或直接报错。原因分析字符集不匹配“三连杀”——文件编码、连接编码、表字段编码不一致。系统性排查确认文件编码如前所述用file -i或编辑器查看。确认MySQL连接编码执行SHOW VARIABLES LIKE character_set_%;关注character_set_client、character_set_connection、character_set_results。建议在连接时或会话中设置为utf8mb4。SET NAMES utf8mb4;确认表和列的字符集SHOW CREATE TABLE your_table;在LOAD DATA语句中显式指定字符集这是最关键的一步确保MySQL按正确的编码解读文件。LOAD DATA INFILE ... CHARACTER SET utf8mb4 ...深度解析CHARACTER SET子句指定的是文件的编码。MySQL会先用这个编码读取文件内容然后在内部转换为连接字符集character_set_connection最后再转换为目标列的字符集进行存储。任何一步转换不支持如从gbk直接转到latin1都会导致乱码或错误。5.7 错误现象数据错列所有数据都挤在第一列或列对应关系混乱问题描述导入后查询发现本该在name列的数据跑到了id列或者整行数据都被当作一个字段。原因分析FIELDS和LINES子句的配置与文件实际格式不符。排查步骤检查字段分隔符用文本编辑器如vim、notepad打开文件查看是否真的是逗号,。有时文件可能使用制表符\t、分号;或竖线|。检查行分隔符这是超级高频错误源。在Linux服务器上用cat -A命令查看文件可以显示所有不可见字符。cat -A /path/to/file.csv如果行尾显示^M$说明是Windows格式\r\n那么LINES TERMINATED BY应该设为\r\n。如果只显示$说明是Unix/Linux格式\n设为\n。如果显示^M说明是旧Mac格式\r设为\r。检查引用符和转义符如果字段内包含分隔符或换行符必须用引用符括起来。检查ENCLOSED BY和ESCAPED BY的设置是否与文件匹配。核对列列表确认INTO TABLE后面指定的列列表顺序、数量是否与文件字段顺序完全对应。如果表有自增ID列但文件没有需要在列列表中排除它或者用SET子句处理。5.8 性能问题导入速度慢甚至导致服务器负载飙升问题描述导入一个几G的文件速度远低于预期数据库服务器CPU或IO很高。原因分析与调优关闭索引针对超大表对于有大量二级索引的表每插入一行都要更新索引这是主要的性能瓶颈。可以在导入前先删除非唯一索引导入完成后再重建。-- 导入前 ALTER TABLE your_table DROP INDEX idx_some_column; -- 执行 LOAD DATA ... -- 导入后 ALTER TABLE your_table ADD INDEX idx_some_column (some_column);警告唯一索引和主键不能删除否则会影响数据完整性。此操作需在业务低峰期进行并评估重建索引的时间。调整事务提交LOAD DATA默认是一个独立的事务。对于超大数据量这个事务会非常巨大产生庞大的undo log可能撑满磁盘。可以分批次导入或者使用mysql客户端的--innodb-batch-size选项如果支持来拆分事务。调整InnoDB参数临时在导入会话中临时调整参数可以提升速度但需谨慎最好在从库或测试环境操作。SET foreign_key_checks 0; -- 关闭外键检查如果表有外键 SET unique_checks 0; -- 关闭唯一性检查确保数据本身唯一 SET sql_log_bin 0; -- 如果是从库或不需要二进制日志可以关闭有主从复制时小心 -- 执行 LOAD DATA ... SET foreign_key_checks 1; SET unique_checks 1; SET sql_log_bin 1;使用CONCURRENT选项MyISAM引擎如果表是MyISAM引擎使用LOAD DATA CONCURRENT可以在导入时允许其他会话读取表但写入仍被阻塞。InnoDB引擎此选项无效。硬件与系统层面确保数据文件放在高速磁盘如SSD上。检查服务器磁盘IO使用率iostat命令避免导入期间其他IO密集型任务争抢资源。6. 进阶技巧与场景化应用掌握了基础操作和排错后再看几个能显著提升效率和可靠性的进阶玩法。6.1 从压缩文件直接导入如果数据文件是gzip压缩的.gz我们不需要先解压。在Linux系统上可以利用命名管道named pipe或进程替换process substitution来实现流式解压导入这对于处理巨大的压缩文件非常节省磁盘空间。# 方法一使用命名管道推荐更直观 mkfifo /tmp/data_pipe.csv gzip -dc /path/to/bigfile.csv.gz /tmp/data_pipe.csv # 然后在另一个终端或后台执行MySQL导入命令从管道读取 mysql -u user -p db_name -e LOAD DATA INFILE /tmp/data_pipe.csv INTO TABLE ... # 导入完成后删除管道文件 rm /tmp/data_pipe.csv # 方法二在LOAD DATA中直接使用进程替换仅支持某些Shell如bash # 注意这需要MySQL有读取 /dev/fd/ 或类似文件描述符的权限且secure_file_priv可能不允许。 # 以下命令在bash中且配置允许时可能有效 mysql -u user -p db_name -e LOAD DATA INFILE /dev/fd/3 INTO TABLE ... 3 (gzip -dc bigfile.csv.gz)核心原理gzip -dc是解压并输出到标准输出。mkfifo创建了一个先入先出的特殊文件gzip向它写LOAD DATA从它读数据像水流一样通过不会在磁盘上产生巨大的临时解压文件。6.2 使用用户变量进行复杂数据清洗SET子句配合用户变量非常强大可以在导入时完成简单的ETL提取、转换、加载。LOAD DATA INFILE /path/to/dirty_data.csv INTO TABLE clean_table FIELDS ... LINES ... (raw_date, dirty_number, description) SET -- 清洗日期将多种格式统一 clean_date CASE WHEN raw_date REGEXP ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ THEN STR_TO_DATE(raw_date, %Y-%m-%d) WHEN raw_date REGEXP ^[0-9]{2}/[0-9]{2}/[0-9]{4}$ THEN STR_TO_DATE(raw_date, %m/%d/%Y) ELSE NULL END, -- 清洗数字移除货币符号和千分位逗号 clean_number CAST(REPLACE(REPLACE(dirty_number, $, ), ,, ) AS DECIMAL(10,2)), -- 清洗文本去除首尾空格将空字符串转为NULL clean_description NULLIF(TRIM(description), ), -- 生成衍生字段从描述中提取关键词 category CASE WHEN description LIKE %error% OR description LIKE %fail% THEN ERROR WHEN description LIKE %warning% THEN WARN ELSE INFO END;6.3 监控导入进度与性能对于超长时间的导入我们想知道进度。虽然LOAD DATA本身不提供进度条但有一些间接方法监控表行数增长在另一个MySQL会话中定期执行SELECT COUNT(*) FROM target_table;。可以配合watch命令Linuxwatch -n 5 mysql -u user -p密码 -e SELECT COUNT(*) FROM db_name.target_table;监控文件读取进度Linux使用lsof命令查看MySQL进程打开了哪个文件以及文件的读取偏移量。sudo lsof -p $(pidof mysqld) | grep /path/to/your/datafile.csv # 输出中会显示文件大小和当前读取位置OFFSET监控服务器状态使用SHOW PROCESSLIST;查看当前执行的命令状态。或者监控InnoDB状态变量SHOW GLOBAL STATUS LIKE Innodb_rows_inserted%; -- 在导入前后分别执行差值就是插入的行数注意这是全局的不只针对当前表。6.4 与主从复制的协同在配置了MySQL主从复制的环境中LOAD DATA语句默认会被记录为二进制日志binlog中的LOAD DATA事件并传输到从库执行。这保证了数据一致性。但需要注意LOCAL关键字的影响如果主库上使用了LOAD DATA LOCAL INFILE由于文件在客户端这个语句在binlog中会被转换为一个普通的LOAD DATA语句但文件内容会以特殊的格式Begin_load_query/Append_block/Exec_load_query事件记录在binlog中。这要求主从库的secure_file_priv设置兼容且从库能找到对应的“伪”文件路径配置较为复杂。生产环境强烈建议避免在主库使用LOCAL。从库性能巨大的LOAD DATA操作在从库回放时同样耗时可能导致主从延迟。可以考虑在从库上暂时关闭二进制日志SET sql_log_bin0;再执行导入如果拓扑结构允许或者使用pt-online-schema-change等在线工具进行数据迁移对复制更友好。
返回列表