通用MySQL CSV文件加载Shell脚本开发可行性问询
你的通用MySQL批量导入方案完全可行!
首先得说,把所有字段统一设为varchar(256)这个思路太务实了——毕竟几十份CSV列结构各不相同,挨个分析字段类型纯纯是浪费时间。varchar(256)能覆盖绝大多数文本、数字甚至短日期的存储需求,后续要是觉得需要优化字段类型(比如把数字列改成int或者decimal),再单独调整也完全没问题,丝毫不影响批量导入的效率。
接下来给你一套完整的实现方案,直接就能用:
一、通用MySQL Shell脚本实现
我写了一个可参数化的JavaScript脚本(MySQL Shell支持JS模式,用起来比SQL脚本灵活多了),能自动遍历指定目录下的CSV,建表+导入一步到位:
1. 脚本代码
// MySQL Shell 批量CSV导入脚本 // 运行方式:mysqlsh -u 你的用户名 -p 你的密码 -h 数据库地址 --execute "source csv_import.js" -- --csv-dir="/你放CSV的目录路径" // 解析命令行传入的CSV目录参数 const args = shell.options.args; const csvDir = args['csv-dir'] || '.'; // 默认当前目录 // 引入文件系统模块,用来读取CSV文件 const fs = require('fs'); const path = require('path'); // 确保已连接到目标数据库(如果没提前连接,就自动连接) if (!session.isConnected()) { session.connect({ user: 'your_db_user', password: 'your_db_pwd', host: 'your_db_host', port: 3306, schema: 'your_target_schema' // 替换成你要导入的数据库名 }); } // 筛选出目录下所有CSV文件 const csvFiles = fs.readdirSync(csvDir).filter(file => file.toLowerCase().endsWith('.csv')); if (csvFiles.length === 0) { print('没有找到任何CSV文件!'); exit(); } // 逐个处理CSV文件 csvFiles.forEach(file => { const fullPath = path.join(csvDir, file); // 生成合法的表名:去掉.csv后缀,把特殊字符换成下划线 const tableName = file.replace(/\.csv$/i, '').replace(/[^a-zA-Z0-9_]/g, '_'); // 读取CSV第一行作为字段名 try { const fileContent = fs.readFileSync(fullPath, 'utf8'); const firstLine = fileContent.split('\n')[0]?.trim(); if (!firstLine) { print(`警告:${file}是空文件,跳过处理\n`); return; } // 处理字段名,转成MySQL合法列名,同时指定类型为varchar(256) const columns = firstLine.split(',').map(col => { const cleanColName = col.replace(/[^a-zA-Z0-9_]/g, '_').trim(); // 避免字段名是MySQL关键字,加反引号 return `\`${cleanColName}\` varchar(256)`; }).join(', '); // 创建表(IF NOT EXISTS避免重复创建报错) const createSql = `CREATE TABLE IF NOT EXISTS \`${tableName}\` (${columns}) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`; print(`正在创建表:${tableName}`); session.sql(createSql).execute(); // 导入数据,处理带引号的字段和换行 const loadSql = ` LOAD DATA INFILE '${fullPath.replace(/\\/g, '/')}' INTO TABLE \`${tableName}\` FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY '\\n' IGNORE 1 ROWS; `; print(`正在导入数据到${tableName}...`); session.sql(loadSql).execute(); print(`${file}处理完成!\n`); } catch (err) { print(`处理${file}出错:${err.message}\n`); } }); print('所有CSV文件处理完毕!');
2. 关键注意事项
- 文件权限:MySQL服务器需要能读取你的CSV文件,最简单的办法是把CSV放到MySQL配置里
secure_file_priv指定的目录;要是嫌麻烦,也可以改成LOAD DATA LOCAL INFILE(从客户端读取文件),但需要确保MySQL客户端开启了local_infile=ON参数 - 特殊字符处理:脚本会自动把字段名和表名里的特殊字符换成下划线,还加了反引号避免和MySQL关键字冲突
- CSV格式兼容:默认处理逗号分隔、双引号包裹字段的标准CSV,如果你的CSV用了其他分隔符(比如制表符),修改
FIELDS TERMINATED BY的值就行
二、额外提速小技巧
- 事务包裹:如果CSV文件比较大,可以在导入前执行
START TRANSACTION;,导入完再COMMIT;,减少磁盘IO的次数 - 关闭约束检查:临时关闭
foreign_key_checks和unique_checks,导入完再打开,能大幅提升导入速度(适合没有外键依赖的场景) - 并行处理:要是服务器性能够,也可以把脚本改成并行处理多个CSV,但单线程对几十份文件来说已经足够快了
内容的提问来源于stack exchange,提问作者JayA
相关产品推荐
相关产品推荐

