我有一张大约有 210 万个元组的表。其中有纬度和经度列。我正在尝试将其转换为地理类型(带有 SRID 的点)。
我写的函数(过程)在我限制条目时工作正常(比如 : SELECT id,longitude,latitude FROM list_of_location limit 50
)。
CREATE OR REPLACE FUNCTION convertlatlon() RETURNS VOID AS $$
DECLARE rec RECORD;
BEGIN
FOR rec IN SELECT id,longitude,latitude FROM list_of_location
LOOP
UPDATE list_of_location SET location= concat('SRID=4326;POINT(',rec.longitude,' ',rec.latitude,')') WHERE id=rec.id;
END LOOP;
END;
$$ LANGUAGE 'plpgsql' ;
- 当我尝试在整个表上运行它时,PostgreSQL 似乎什么都不做。已经等了一个半小时。
- 在其运行的核心上消耗 99% 的 CPU。
- 不会启动任何其他 PostgreSQL 实例来利用其他核心(因为请求来自单个用户?)。
- 这是因为锁(行级别)吗?
- 如何规避这个?
在循环内运行 DML 语句从来都不是一个好主意。您正在成倍增加要完成的工作量。关系数据库在对集合进行操作时是最好的,当您执行循环时,您一次只对一行进行操作。
您可以通过在单个语句中执行更新来实现相同的目的:
我不是 100% 了解计算实际点的语法,因为我不使用几何学的东西,但我想你会明白的。
我建议你不要只在一个函数中完成所有工作,因为函数是 PostgreSQL 中的事务,全部完成或全部不完成!如果表很大,你可能需要花费很多时间来完成这项工作,并且在过程中,表的整行都被锁定(row level lock)。
所以我建议采用下面的方法,我们可以每隔1000或10000行做一次,这样我们就不需要锁住表的整行(行级锁),而且对生产数据库的影响很小。
--1 创建tmp表
--2 创建函数
通过查询表tmp_location。
--3 vi func_file.sql
如果表中有 200 万行,你需要写很多行的“select convertlatlon();”,所以你应该在文件 func_file.sql 中写 2000 (2000000/1000) 行
- -4 执行函数
--vi 1.sh
- -执行函数
你应该在后台执行作业,因为它需要很多时间。