osm2pgsql搭配自定义Lua配置处理数据耗时过长求助
针对你的情况,结合脚本和运行参数,核心瓶颈大概率出在Lua层的几何计算、数据库配置以及运行参数选择上,以下是具体排查和优化方向:
1. Lua中提前做几何变换+长度计算是最大性能杀手
你的脚本在process_way里直接执行:
dist = geom:transform(srid):length()
这是把原本可以交给PostgreSQL高效处理的投影变换和长度计算,放在了Lua里完成——Lua的几何运算性能远低于PostgreSQL的C实现,尤其是处理大量道路数据时,这个操作会累积成巨大的耗时。
参考的route-relations脚本应该是把几何数据以WGS84(EPSG:4326)存入数据库,再通过PostgreSQL的ST_Transform和ST_Length计算,或者干脆在表定义时指定投影,让osm2pgsql内部用C代码处理投影(比Lua快得多)。
优化方案:
- 把
dist字段的计算移到数据库端:- 去掉Lua脚本里
dist = geom:transform(srid):length()这行,表定义里保留dist字段但不设置默认值。 - 数据导入完成后,执行SQL更新:
UPDATE berlin.ways SET dist = ST_Length(geom);
- 去掉Lua脚本里
- 或者,保持表定义里的
geom投影设置,但删除Lua中的手动transform,让osm2pgsql内部处理投影(它会用更高效的C代码完成),然后在数据库里计算长度。
2. 检查--slim参数是否必要
你的运行命令加了--slim,这个参数会启用slim模式,osm2pgsql会创建中间表存储所有节点、way的原始数据,方便后续增量更新,但代价是大量额外的磁盘IO和写入操作。如果你的场景不需要增量更新,完全可以去掉这个参数,这会大幅减少耗时。
参考脚本的测试命令大概率没加--slim,这是两者耗时差异的重要原因之一。
3. 数据库配置优化
即使你用了高速SSD,如果PostgreSQL的配置没跟上,也会拖慢写入速度:
- 临时调高
shared_buffers(比如设为2GB,你的笔记本有8GB内存)、work_mem(比如64MB)、maintenance_work_mem(比如512MB)。 - 导入期间关闭
wal_level(设为minimal)、禁用autovacuum,导入完成后再改回。 - 确保数据库的
temp_tablespaces放在SSD上。
4. 脚本细节的小优化
(1) 避免clean_tags修改原对象
你的clean_tags直接修改了传入的tags对象,可能带来潜在的逻辑冲突,建议改为创建副本后修改:
function clean_tags(tags) local cleaned = {} for k, v in pairs(tags) do if k ~= 'odbl' and k ~= 'created_by' and k ~= 'source' and k ~= 'source:ref' then cleaned[k] = v end end return next(cleaned) == nil, cleaned end
然后在处理函数里使用返回的清理后标签:
local is_empty, cleaned_tags = clean_tags(object.tags) if is_empty then return end row.tags = cleaned_tags
(2) 简化rel_ids的构造
你手动拼接数组字符串'{' .. table.concat(ids, ',') .. '}',可以改用osm2pgsql的原生数组支持,直接传入Lua数组:
row.rel_ids = ids
表定义里的rel_ids类型保持sql_type = 'int8[]'即可,osm2pgsql会自动处理格式转换,比手动拼接更高效且不易出错。
5. 验证脚本的过滤逻辑
检查你的过滤条件是否比参考脚本更宽松,导致导入了更多数据:
- 比如
process_node里你导入了shop、bar/cafe、公交站,而参考脚本可能只导入了公交相关节点。 process_way里你包含了所有highway类型,参考脚本可能只筛选了公交相关的道路。
不过柏林的PBF只有74MB,即使多导入一些数据也不至于慢到几小时,所以这个不是核心原因,但可以确认下。
内容的提问来源于stack exchange,提问作者evan

