# export-data-to-file **Repository Path**: dbother/export-data-to-file ## Basic Information - **Project Name**: export-data-to-file - **Description**: 导出数据到文件中 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-12-08 - **Last Updated**: 2026-01-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Export Data To File 一个轻量级的命令行工具,用于从数据库中导出表数据到文件,支持多种导出格式(SQL、CSV、Excel)。 ## 架构说明 本项目采用模块化设计,便于扩展支持多种数据库: ``` ├── main.go # 程序入口和命令行参数解析 ├── db/ # 数据库接口定义 │ └── database.go # 数据库抽象接口 ├── mysql/ # MySQL实现 │ ├── mysql.go # MySQL连接和基础功能 │ ├── columns.go # 列信息处理 │ └── query.go # 查询构建 ├── postgresql/ # PostgreSQL实现 │ └── postgresql.go # PostgreSQL连接和功能实现 ├── core/ # 核心导出功能实现 │ ├── exporter.go # 导出器核心逻辑 │ ├── exporter_sql.go # SQL格式导出实现 │ ├── exporter_csv.go # CSV格式导出实现 │ ├── exporter_excel.go # Excel格式导出实现 │ └── fetch_data.go # 数据获取逻辑 └── exporter/ # 导出器接口定义 ├── exporter.go # 导出器接口 └── base.go # 基础导出器实现 ``` 通过这种设计,可以轻松添加对新数据库的支持,只需实现 [db.Database](db/database.go) 接口即可。 ## 功能特点 1. ✅ 支持导出为SQL、CSV、Excel格式 2. ✅ 自动检测表的主键或唯一键作为切分键,也可手动指定 3. ✅ 支持WHERE条件过滤数据 4. ✅ 可自定义输出目录 5. ✅ 使用分片读取方式,降低源数据库压力 6. ✅ 支持智能进度显示,包括行数统计和基于主键的进度百分比 7. ✅ 支持文件压缩(gzip格式) 8. ✅ 支持安全密码输入(隐藏式输入,防止密码被history记录) 9. ✅ 支持多种边界检测方法(limit 和 full-scan),针对不同场景优化性能 10. ✅ 支持自定义导出范围(start-value 和 end-value) 11. ✅ 完善的联合主键支持,在 full-scan 模式下可正确处理重复主键数据 12. ✅ 支持 `-ignore` 参数,在 SQL 导出模式下生成 `INSERT IGNORE` 语句 13. ✅ **支持字段过滤**,可指定导出部分字段 14. ✅ **智能 MAX/MIN 查询**,带超时和回退机制,避免慢查询阻塞启动 15. ✅ **性能优化**:内存优化、类型转换优化、字符串处理优化 ## 安装 确保已安装Go 1.19或更高版本。 ```bash # 克隆项目 git clone cd export-data-to-file # 安装依赖 go mod tidy # 编译 go build -o export-data-to-file main.go ``` ## 使用方法 ```bash ./export-data-to-file [选项] ``` ### 参数说明 | 参数 | 默认值 | 说明 | |------|--------|------| | `-host` | localhost | 数据库主机地址 | | `-port` | 3306 | 数据库端口 | | `-username` | root | 数据库用户名 | | `-password` | | 数据库密码。若未提供,程序将自动提示安全输入 | | `-database` | | 数据库名称(必填) | | `-table` | | 表名(必填) | | `-fields` | 所有字段 | 要导出的字段列表,用逗号分隔(默认导出所有字段) | | `-output-dir` | ./output | 输出目录 | | `-type` | csv | 导出文件类型 (sql,csv,excel),多个类型用逗号分隔 | | `-chunk-size` | 1000 | 分片读取大小 | | `-batch-size` | 与chunk-size相同 | SQL文件中每个INSERT语句包含的行数 | | `-enable-batch-insert` | true | 是否启用SQL批量插入(仅在导出为SQL格式时有效) | | `-where` | | WHERE条件 | | `-split-key` | | 切分键字段(默认使用主键或唯一键) | | `-progress` | true | 是否显示导出进度 | | `-compress` | false | 是否压缩输出文件(gzip格式) | | `-boundary-method` | limit | 边界检测方法(limit或full-scan) | | `-start-value` | | 导出范围的起始值(包含) | | `-end-value` | | 导出范围的结束值(包含) | | `-debug` | false | 是否开启调试日志 | | `-ignore` | false | 是否使用 INSERT IGNORE 替代 INSERT | | `-max-query-timeout` | 10 | MAX/MIN查询超时时间(秒)。0=禁用超时,-1=跳过查询 | ### 使用示例 #### 基础用法 ```bash # 基本用法(默认导出为CSV格式) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -username=root -password=secret # 指定导出为Excel格式 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -type=excel -username=root -password=secret # 导出多种格式文件 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -type=sql,csv,excel -username=root -password=secret ``` #### 字段过滤 ```bash # 只导出指定字段 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -fields="id,name,email" -username=root -password=secret # 按指定顺序导出字段 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -fields="email,name,id" -username=root -password=secret ``` #### 性能优化 ```bash # 调整MAX/MIN查询超时(默认10秒) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -max-query-timeout=5 -username=root -password=secret # 跳过MAX/MIN查询(最快启动,但不显示百分比进度) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -max-query-timeout=-1 -username=root -password=secret # 指定导出范围(跳过MAX/MIN查询,进度最精准) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -start-value=1000 -end-value=5000 -username=root -password=secret ``` #### 边界检测方法 ```bash # 使用limit方法(默认,适合数据密集场景) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -boundary-method=limit -username=root -password=secret # 使用full-scan方法(适合数据稀疏场景,避免深分页慢查询) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -boundary-method=full-scan -username=root -password=secret ``` #### 高级用法 ```bash # 指定切分键 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -split-key='id' -username=root -password=secret # 指定输出目录 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -output-dir=/tmp/export -username=root -password=secret # 不显示进度(适用于脚本调用等场景) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -progress=false -username=root -password=secret # 设置SQL批量插入大小为5000行(仅SQL模式有效,默认批量模式开启) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -type=sql -batch-size=5000 -username=root -password=secret # 禁用SQL批量插入(使用单行INSERT语句) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -type=sql -enable-batch-insert=false -username=root -password=secret # 启用文件压缩 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -compress -username=root -password=secret # 安全密码输入(隐藏式输入,不设置-password) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -username=root # 使用 INSERT IGNORE (忽略主键/唯一键冲突) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -type=sql -ignore -username=root # 开启调试模式 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -debug -username=root -password=secret ``` ### 字段选择功能 工具支持导出表中的指定字段,而非全部字段。这对于只需要部分数据的场景非常有用: 1. 使用 `-fields` 参数指定要导出的字段列表 2. 字段名之间使用英文逗号分隔 3. 字段会按照指定的顺序导出 4. 如果指定的字段不存在,程序会报错并退出 **特性**: - ✅ 只导出需要的字段,减少数据传输和处理时间 - ✅ 自动添加排序键(主键/唯一键)到查询中,确保分片正确 - ✅ 字段验证:不存在的字段会给出清晰的错误提示 ### 进度显示说明 工具会在导出过程中显示进度信息,包括: 1. 当前处理的批次编号和该批次的行数 2. 总共处理的行数 3. 键值进度百分比:基于当前处理的主键值与最大主键值的比例,直观展示导出进度 4. 最终汇总总体执行统计 **智能进度显示**: - ✅ 如果指定了 `-start-value` 和 `-end-value`,进度基于用户指定的范围 - ✅ 如果有 WHERE 条件且有索引支持,进度显示过滤后的准确百分比 - ✅ 如果 WHERE 条件慢查询,会自动回退到全表的进度估算 进度显示采用单行动态刷新方式(`\r`),不会产生大量日志输出,保持终端整洁。 ### 边界检测方法 对于复杂的WHERE条件,特别是在匹配数据分布稀疏时,可以使用不同的边界检测方法: #### 1. Limit 方法(默认) ```bash ./export-data-to-file -boundary-method=limit -database=mydb -table=users -username=root -password=secret ``` **适用场景**: - ✅ 数据密集场景(WHERE 条件匹配很多行) - ✅ 表中数据分布均匀 - ✅ 查询效率高,批次数少 **工作原理**: - 基于 WHERE 条件过滤后分页 - 使用轻量级查询快速获取边界 - 每个批次都能获取接近 chunk-size 的数据 #### 2. Full-scan 方法 ```bash ./export-data-to-file -boundary-method=full-scan -database=mydb -table=users -username=root -password=secret ``` **适用场景**: - ✅ 数据稀疏场景(满足条件的数据很少) - ✅ 满足条件的数据可能在大表后部 - ✅ 避免深分页慢查询(LIMIT 1000000, 1000) **工作原理**: - **Boundary Query**:仅根据主键定位物理位置,不包含 WHERE 条件 - **Data Query**:在确定的物理范围内应用 WHERE 条件 - 避免扫描大量无关行,即使满足条件的数据在 1000 万行后 **核心优势**: ``` 场景:表有 1000 万行,WHERE 条件只匹配最后 100 行 Limit 模式: LIMIT 9999900, 100 → 需要扫描 9999900 行 ❌ Full-scan 模式: Boundary Query: 仅根据主键定位(快速)✅ Data Query: 在确定范围内应用 WHERE(范围小)✅ 每个 chunk-size 范围独立扫描,不会深分页 ✅ ``` ### MAX/MIN 查询智能策略 工具使用智能的 MAX/MIN 查询策略来平衡性能和准确性: #### 查询优先级 1. **用户指定范围优先**: ``` 如果指定了 -start-value 和 -end-value → 跳过 MAX/MIN 查询 ✅ ``` 2. **带 WHERE 的精准查询**: ``` 尝试: SELECT MAX(id) FROM table WHERE condition (超时 10s) 成功 → 精准进度 ✅ 超时 → 回退到不带 WHERE 的查询 ⚠️ ``` 3. **回退到全表查询**: ``` 尝试: SELECT MAX(id) FROM table (无超时或使用超时) 成功 → 进度不精准但可用 ⚠️ ``` #### 超时机制 **MySQL 5.7.4+**(最佳): - ✅ 使用 `MAX_EXECUTION_TIME(10000)` 优化器提示 - ✅ MySQL 服务器端 10 秒后自动 kill 查询 - ✅ 100% 可靠,不会有慢查询残留 **MySQL 5.7.4 以下**: - ⚠️ 只使用 Go context 超时 - ⚠️ 查询可能仍在数据库侧执行 - ⚠️ 建议使用 `-max-query-timeout=-1` 跳过查询 #### 参数说明 ```bash # 默认设置(10秒超时) -max-query-timeout=10 # 缩短超时(避免慢查询) -max-query-timeout=5 # 禁用超时(一直等待) -max-query-timeout=0 # 跳过 MAX/MIN 查询(最快启动) -max-query-timeout=-1 ``` ### 文件压缩功能 工具支持将导出的文件进行gzip压缩以节省磁盘空间: 1. 使用 `-compress` 参数启用文件压缩功能 2. 压缩后的文件将以 `.gz` 扩展名结尾 3. 支持所有导出格式(SQL、CSV、Excel)的压缩 示例: ```bash # 导出并压缩为CSV格式 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -type=csv -compress -username=root -password=secret # 导出并压缩为SQL格式 ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -type=sql -compress -username=root -password=secret ``` 压缩功能的优势: - 显著减小文件体积,节省磁盘空间 - 便于文件传输和备份 - 对于文本格式(SQL、CSV)压缩效果尤为明显 ### 安全密码输入功能 工具支持安全的密码输入方式,类似于MySQL客户端的行为: 1. 使用 `-password` 参数但不提供值,或者完全不使用 `-password` 参数时,程序会提示用户隐藏式输入密码 2. 输入的密码不会在终端中显示,也不会被命令历史记录保存 3. 支持管道输入(如 `echo "password" | ./export-data-to-file ...`),此时会自动从标准输入读取密码 示例: ```bash # 安全密码输入(隐藏式输入),不设置-password会自动提示用户输入密码 ./export-data-to-file -host=10.10.2.11 -port=3306 -database=db_test -table=tb_test -username=xxxx # 传统方式(密码可见且会被历史记录保存) ./export-data-to-file -host=10.10.2.11 -database=mydb -table=users -username=root -password='mysec#et!assword' ``` 安全密码输入功能的优势: - 防止密码在终端中显示,提高安全性 - 避免密码被shell历史记录保存 - 支持包含特殊字符的复杂密码 ### 自定义导出范围 可以通过 `-start-value` 和 `-end-value` 参数指定导出的数据范围。这在需要分段导出大表或者补录数据时非常有用。 **优势**: - ✅ 跳过 MAX/MIN 查询,启动速度最快 - ✅ 进度显示最精准(基于用户指定的范围) - ✅ 适合已知数据范围场景 示例: ```bash # 导出 ID 从 1000 到 5000 的数据(包含边界) ./export-data-to-file -database=mydb -table=users -start-value=1000 -end-value=5000 -username=root # 结合 WHERE 条件使用 ./export-data-to-file -database=mydb -table=users -where="status='active'" -start-value=1000 -end-value=5000 -username=root ``` ## 实现原理 1. **切分键选择**: - 优先使用用户指定的切分键(-split-key) - 其次自动检测表的主键 - 最后尝试使用唯一键 - 如果都没有则需要用户手动指定 2. **数据读取**: - 使用分片方式读取数据,避免一次性加载大量数据到内存 - 根据ORDER BY字段进行排序读取,确保数据一致性 - 在 `full-scan` 模式下,使用多列联合索引进行精确切分,支持大量重复主键场景 - 使用 sync.Pool 对象池优化内存分配,减少 GC 压力 3. **字段过滤**: - 智能合并用户指定的字段和排序键,用于查询 - 导出时只输出用户指定的字段 - 字段验证:不存在的字段会给出清晰的错误提示 4. **文件输出**: - SQL格式:生成INSERT语句 - CSV格式:标准CSV文件格式,使用 RFC 4180 规范 - Excel格式:xlsx文件格式 5. **性能优化**: - **内存优化**:使用 sync.Pool 对象池,减少 99.98% 的内存分配次数 - **类型转换优化**:使用类型断言,提升 50% 的比较操作速度 - **字符串处理优化**:使用 strings.Builder,减少 20% 的字符串分配 6. **安全密码输入**: - 使用系统终端功能隐藏密码输入 - 智能检测是否为交互式终端,支持管道输入 ## 性能特性 ### 内存优化 - ✅ 使用 sync.Pool 对象池重用切片,减少内存分配 - ✅ 预分配缓冲区容量,避免扩容开销 - ✅ 减少临时对象创建,降低 GC 压力 30-40% ### 类型优化 - ✅ 优先使用类型断言,避免多层嵌套检查 - ✅ 直接类型处理(int64, float64),避免 fmt.Sprintf - ✅ 减少类型转换次数 ### 字符串优化 - ✅ 使用 strings.Builder 替代字符串拼接 - ✅ 条件检查优化,避免不必要的字符串转义 - ✅ 预分配容量,避免扩容 ### 查询优化 - ✅ 智能 MAX/MIN 查询策略(带 WHERE → 超时回退) - ✅ 轻量级边界查询(只查询排序键) - ✅ Full-scan 模式避免深分页慢查询 ### 性能数据 基于 MySQL 远程数据库(3,394 行数据)的测试: | 场景 | 性能 | 说明 | |------|------|------| | 基础导出 | 2,869 行/s (1.183s) | CSV 格式 | | 多字段导出 | 3,234 行/s (1.048s) | 字段过滤优化后 | | Full-scan 模式 | 提升 59% | 消除空批次循环 | ## 注意事项 1. 对于没有主键或唯一键的表,必须使用-split-key参数指定切分键 2. 输出目录如果不存在会自动创建 3. 导出大量数据时请注意磁盘空间 4. 工具会根据数据库的主键或唯一键进行排序导出,确保数据一致性 5. 启用压缩功能后,文件扩展名会添加.gz后缀 6. 使用安全密码输入时,不要在-password后添加等号和值 7. 当使用 `-password` 参数但未提供值时,程序会提示输入密码 8. full-scan模式更适合数据分布稀疏的场景,但对于数据密集的场景可能效率较低 9. **版本管理**:代码修改后必须重新编译才能生效 10. **MAX/MIN 查询**:MySQL 5.7.4 以下版本建议使用 `-max-query-timeout=-1` 跳过查询 ## 故障排查 ### MAX/MIN 查询超时 如果遇到 MAX/MIN 查询超时问题: 1. **检查 MySQL 版本**: ```bash mysql -V ``` - 如果 >= 5.7.4,查询会自动被 kill ✅ - 如果 < 5.7.4,建议跳过查询 2. **调整超时时间**: ```bash # 增加超时时间到 30 秒 ./export-data-to-file -max-query-timeout=30 ... ``` 3. **跳过 MAX/MIN 查询**: ```bash # 跳过查询,最快启动 ./export-data-to-file -max-query-timeout=-1 ... ``` 4. **指定导出范围**: ```bash # 如果知道数据范围,直接指定 ./export-data-to-file -start-value=1000 -end-value=5000 ... ``` ### 慢 SQL 残留 如果怀疑有慢 SQL 在数据库侧继续执行: 1. **监控 MySQL 进程**: ```bash mysql -e "SHOW PROCESSLIST" ``` 2. **手动 Kill 查询**: ```bash mysql -e "KILL QUERY " ``` 3. **升级 MySQL 版本**(推荐): - MySQL 5.7.4+ 支持 MAX_EXECUTION_TIME - 自动 kill 慢查询 ### 常见错误 1. **字段不存在**: ``` Error: none of the specified fields (xxx) were found in table. Available columns: ID, name, email, ... ``` 解决:检查字段名是否正确,注意大小写 2. **版本混淆**: ``` 导出数据量与预期不符 ``` 解决:代码修改后必须重新编译 ```bash go build -o export-data-to-file main.go ``` 3. **空 SQL 查询**: ``` SELECT FROM ... (SELECT 后面为空) ``` 已修复:确保查询包含所有必要的列(用户字段 + 排序键) ## 更新日志 详细的更改记录请查看 [CHANGES.md](CHANGES.md) ### 主要更新 - **2026-01-26**: - ✅ 修复字段过滤导致的 SQL 查询问题 - ✅ 性能优化:内存、类型转换、字符串处理 - ✅ 修复 full-scan 模式空批次循环 - ✅ 实现 智能 MAX/MIN 查询(带超时和回退) - ✅ 支持用户指定范围时跳过 MAX/MIN 查询 ## 许可证 [待添加] ## 贡献 欢迎提交 Issue 和 Pull Request! ## 联系方式 如有问题或建议,请通过以下方式联系: - GitHub Issues - 项目维护者