Tenho uma tabela com aproximadamente 2,1 milhões de tuplas. Que tem colunas de latitude e longitude. Estou tentando converter isso em um tipo geográfico (apontar com SRID).
A função (procedimento) que escrevi funciona bem quando limito as entradas (digamos: 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' ;
- Quando tento executá-lo em toda a tabela, o PostgreSQL parece não fazer nada. Esperei por uma hora e meia.
- Consome 99% da CPU no núcleo em que está rodando.
- Não gera nenhuma outra instância do PostgreSQL para utilizar outros núcleos (já que a solicitação é de um único usuário?).
- Isso é por causa de bloqueios (nível de linha)?
- Como contornar isso?
Executar uma instrução DML dentro de um loop nunca é uma boa ideia. Você está multiplicando a quantidade de trabalho a ser feito. Bancos de dados relacionais são melhores ao operar em conjuntos, quando você faz um loop, você está operando em uma única linha por vez.
Você pode conseguir o mesmo fazendo a atualização em uma única instrução:
Não sou 100% sobre a sintaxe para calcular o ponto real, pois não uso material geométrico, mas acho que você entenderá.
Sugiro a você que não faça todo o trabalho em apenas uma função, pois função é uma transação no PostgreSQL, tudo feito ou tudo não feito! E se a tabela for muito grande, você pode levar muitas horas para realizar esse trabalho, e durante o processo, toda a linha da tabela está bloqueada ( bloqueio de nível de linha)。
Então, sugiro o seguinte método, podemos fazer esse trabalho a cada 1.000 ou 10.000 linhas, para que não precisemos bloquear toda a linha da tabela (bloqueio em nível de linha), e isso tem um pequeno impacto no banco de dados de produção。
--1 cria tabela tmp
--2 criar função
consultando a tabela tmp_location。
--3 vi func_file.sql
você precisa escrever muitas linhas do "select convertlatlon ();", se você tiver 2 milhões de linhas na tabela, então você deve escrever 2000 (2000000/1000) linhas no arquivo func_file.sql
- -4 executa a função
--vi 1.sh
- -função de execução
você deve executar o trabalho em segundo plano, porque leva muito tempo.