Linux中封装数据表增量导出函数,核心是将“识别新增/变更数据”“安全连接数据库”“分批导出”“结果格式化”四环节打包成可复用、可传参、可审计的shell函数,支持时间字段与主键两种增量模式,校验参数、防SQL注入、统一字符集、分批导出并记录断点。

Linux中封装数据表增量导出函数,核心是把“识别新增/变更数据”“安全连接数据库”“分批导出”“结果格式化”四个环节打包成可复用、可传参、可审计的 shell 函数。不依赖外部脚本,也不硬编码密码或路径,重点解决生产环境常见的权限、大表、字符集、断点续导等问题。
明确增量依据并支持灵活传参
增量导出必须有可靠位点,常见方式包括:
- 基于时间字段(如 create_time 或 update_time),需用户指定起止时间或偏移量
- 基于自增主键(如 id),需传入上次导出的最大值(--last-id)
- 基于 binlog 位点(适合配合 Xtrabackup 或 mysqlbinlog 工具,函数内一般不直接处理,但可预留接口)
函数应支持至少两种模式切换,并校验必要参数:
mysql_incremental_export() {
local db="" table="" field="" since="" until="" last_id="" output_dir="/tmp"
local user="root" host="localhost" use_table=0
<p>while [[ $# -gt 0 ]]; do
case $1 in
-d) db="$2"; shift 2 ;;
-t) table="$2"; shift 2 ;;
--time-field) field="$2"; shift 2 ;;
--since) since="$2"; shift 2 ;;
--until) until="$2"; shift 2 ;;
--last-id) last_id="$2"; shift 2 ;;
--output) output_dir="$2"; shift 2 ;;
--table) use_table=1; shift ;;
*) echo "Unknown option: $1"; return 1 ;;
esac
done</p><p>if [[ -z "$db" || -z "$table" ]]; then
echo "Error: -d DATABASE and -t TABLE are required" >&2; return 1
fi</p><p>if [[ -n "$since" && -n "$last_id" ]]; then
echo "Error: cannot specify both --since and --last-id" >&2; return 1
fi
}构造安全、可读的导出命令
避免明文密码暴露,优先使用 mysql_config_editor 配置登录路径;若必须传密,用 -p 交互式输入而非 -ppasswd;导出时强制指定字符集防止乱码:
- 用 --default-character-set=utf8mb4 统一编码
- 用 --fields-terminated-by='\t' 或 --fields-enclosed-by='\"' 控制 CSV 格式
- 对时间范围导出,SQL 中用 STR_TO_DATE() 或直接拼接字符串(注意 SQL 注入风险,建议用变量校验)
- 对主键范围导出,SQL 中写成 WHERE id > $last_id ORDER BY id LIMIT 10000
示例片段:
local sql=""
if [[ -n "$since" ]]; then
sql="SELECT * FROM \`${table}\` WHERE \`${field}\` >= '$since'"
[[ -n "$until" ]] && sql="$sql AND \`${field}\` < '$until'"
elif [[ -n "$last_id" ]]; then
sql="SELECT * FROM \`${table}\` WHERE id > $last_id ORDER BY id LIMIT 10000"
else
echo "Error: either --since or --last-id must be provided" >&2; return 1
fi
<p>local cmd="mysql -u$user -h$host -D$db --default-character-set=utf8mb4 -N -s"
[[ $use_table -eq 1 ]] && cmd="$cmd --table"</p><h1>导出到文件,带时间戳防覆盖</h1><p>local outfile="${output<em>dir}/${table}</em>$(date +%Y%m%d_%H%M%S).csv"
eval "$cmd -e \"$sql\"" | sed '/^$/d' > "$outfile"
echo "Exported to: $outfile"支持分批导出与断点记录
单次导出不宜过大,尤其面对千万级以上表。函数可内置循环逻辑,每次取固定行数,并自动更新 last_id 到文件:
- 用 SELECT MAX(id) 获取本次导出最大值
- 将该值追加写入 ${table}.lastid 文件供下次调用读取
- 加 sleep 0.1 防止密集查询压垮库
- 导出前检查磁盘空间(df -B1M $output_dir | awk 'NR==2 {print $4}')
例如分页逻辑节选:
local current_id=$last_id
while true; do
local batch_sql="SELECT id, * FROM \`${table}\` WHERE id > $current_id ORDER BY id LIMIT 5000"
local result=$(eval "$cmd -e \"$batch_sql\"" 2>/dev/null)
<p>if [[ -z "$result" ]]; then break; fi</p><h1>提取本批最大 id</h1><p>current_id=$(echo "$result" | tail -n1 | cut -f1)</p><h1>追加写入文件</h1><p>echo "$result" | tail -n +1 >> "$outfile"
echo "Batch done, last id: $current_id"
sleep 0.1
done</p><p>echo "$current_id" > "${output_dir}/${table}.lastid"输出控制与错误兜底
生产函数必须自带基础健壮性:
- 执行前检查 mysql 命令是否存在
- 导出后用 wc -l 校验行数,非零才认为成功
- 失败时打印完整命令和错误码($?),便于排查
- 支持静默模式(--quiet)和调试模式(--debug 输出 SQL)
不复杂但容易忽略。


















