优化读取大型GML文件的Bash脚本效率
问题分析与优化方案
低效点根源
- Bash作为Shell语言,**单条循环+频繁调用外部命令(如
bc、sed)**是核心性能瓶颈:每次调用外部命令都会创建新进程,1000条记录就要启动数千次进程,开销极大。 - Bash数组遍历和字符串拼接的原生性能差:每次字符串拼接(如
sql+=...)都会重新分配内存,数据量越大,性能衰减越明显。 - 逐行生成单条
INSERT语句:后续MySQL插入时要处理1000次单条插入,额外增加数据库交互开销。
优化方案
核心思路是用awk替代Bash完成所有文本/数值处理,并生成批量插入的SQL语句,全程减少进程切换和数据库交互次数。
1. 用awk完成坐标解析、极值计算与SQL拼接
awk专为文本处理设计,单进程运行,内置数值计算能力,无需调用bc等外部命令,性能远高于Bash循环。
示例脚本(假设从xmllint输出中提取的每条记录格式为[ID] [坐标串],比如1 51.5074 -0.1278 51.5075 -0.1277 51.5073 -0.1276):
BEGIN { # 初始化批量SQL前缀 print "INSERT INTO land_polygons (id, coordinates, min_lat, max_lat, min_lon, max_lon) VALUES" first_record = 1 } # 处理每条记录 { id = $1 coords = "" min_lat = 999; max_lat = -999 min_lon = 999; max_lon = -999 # 遍历坐标对(从第2个字段开始,步长2) for (i=2; i<=NF; i+=2) { lat = $i lon = $(i+1) coords = coords lat " " lon " " # 更新极值 if (lat < min_lat) min_lat = lat if (lat > max_lat) max_lat = lat if (lon < min_lon) min_lon = lon if (lon > max_lon) max_lon = lon } # 去除坐标串末尾空格 sub(/ $/, "", coords) # 拼接SQL行,处理逗号分隔 if (first_record) { printf "('%s', '%s', %.6f, %.6f, %.6f, %.6f)", id, coords, min_lat, max_lat, min_lon, max_lon first_record = 0 } else { printf ",\n('%s', '%s', %.6f, %.6f, %.6f, %.6f)", id, coords, min_lat, max_lat, min_lon, max_lon } } END { # 结束SQL语句 print ";" }
2. 整合xmllint与awk,减少中间文件
直接将xmllint的输出通过管道传给awk,避免写入临时文件,进一步提升效率:
xmllint --xpath "//gml:Polygon[...]/gml:posList/text()" input.gml | awk -f process_coords.awk > bulk_insert.sql
(注:替换xpath表达式为你实际提取ID和坐标的逻辑,确保输出每条记录为ID 坐标串格式)
3. 批量导入MySQL
生成的bulk_insert.sql是单条批量插入语句,导入时只需一次数据库交互,速度远快于1000条单条插入:
mysql -u username -p database_name < bulk_insert.sql
示例效果
输入示例坐标数据
1 51.5074 -0.1278 51.5075 -0.1277 51.5073 -0.1276 2 52.6309 -1.1398 52.6310 -1.1397 52.6308 -1.1399
生成的SQL插入语句
INSERT INTO land_polygons (id, coordinates, min_lat, max_lat, min_lon, max_lon) VALUES ('1', '51.5074 -0.1278 51.5075 -0.1277 51.5073 -0.1276', 51.507300, 51.507500, -0.127800, -0.127600), ('2', '52.6309 -1.1398 52.6310 -1.1397 52.6308 -1.1399', 52.630800, 52.631000, -1.139900, -1.139700);
额外优化建议
- 如果GML文件极大,可修改awk脚本,每10000条记录生成一个批量插入语句,避免生成的SQL文件过大。
- 确保MySQL表字段类型匹配:
coordinates用TEXT或VARCHAR,经纬度字段用DECIMAL(10,6)类型,提升存储和查询效率。
内容的提问来源于stack exchange,提问作者joe.mse
相关产品推荐
相关产品推荐

