1

我正在尝试使用另一个表 (B) 中包含的地址数据对一个表 (A) 中的数据进行地理编码。由于街道名称的写法可能不同,我想先浏览 A 中的数据,然后在给定的邮政编码区域内,为每个元组找到 B 中最接近 A 元组中的街道名称的街道名称。对于文本匹配,我目前正在使用 pg_trgm 扩展中的similarity() 函数和'%' 运算符。

A 包含来自不同国家的数据,因此函数参数包含相应的表名称,还包含我正在处理的国家和地址数据表 (B) 中相关字段的名称。

各表中的相关字段为:

一个

id            | bigint                | non NULL
cp            | character varying     |
rue           | character varying     | 
rue_trouvee   | character varying     | 
iso_pays      | character varying     | 

带索引:

"tableA_temp_pkey" PRIMARY KEY, btree (id)
"idx_tableA_pays" btree (iso_pays)

rue              | character varying(90) | 
code_post        | character varying(5)  | 
x                | double precision      | 
y                | double precision      | 

带索引:

"idx_fradresses_code_post" btree (code_post)
"idx_fradresses_rue_trgm" gin (rue gin_trgm_ops)

目前,我正在使用这个 PLPGSQL 函数:

CREATE OR REPLACE FUNCTION trouver_rue_proche(datatable TEXT, addresstable TEXT, address_rue TEXT, address_cp TEXT, pays TEXT) RETURNS INTEGER AS $$
DECLARE

rec_data RECORD;
nom_rue RECORD;

counter INTEGER;

BEGIN

    counter := 0; 

    FOR rec_data IN
       EXECUTE SELECT id, rue, cp FROM ' || quote_ident(datatable) || ' WHERE iso_pays = ' || quote_literal(pays) || ' AND x is null'
   LOOP

       counter := counter + 1;
       EXECUTE 'SELECT ' || quote_ident(address_rue) || ' as rue_t FROM geocode.' ||   quote_ident(addresstable) || ' WHERE ' || quote_ident(address_cp) || ' = ' || quote_literal(rec_data.cp) || ' AND ' || quote_ident(address_rue) || ' % ' || quote_literal(rec_data.rue) || ' ORDER BY similarity(' || quote_ident(address_rue) || ', ' || quote_literal(rec_data.rue) || ') DESC LIMIT 1' INTO nom_rue;
       EXECUTE 'UPDATE ' || quote_ident(datatable) || ' SET rue_trouvee = $1 WHERE id = $2' USING nom_rue.rue_t, rec_data.id;
    END LOOP;

    RETURN counter;

END

$$

LANGUAGE plpgsql;

当尝试为一个有 584,670 个元组仍然有 x=NULL 并且地址表包含 25,228,340 个元组的国家/地区运行此函数时,该函数已经运行了将近 3 天。

我的机器有以下规格:

Intel(R) Core(TM) i3-3225 CPU @ 3.30GHz
8GB RAM

我在 postgresql.conf 中使用以下参数运行 PostgreSQL 9.1:

shared_buffers = 4096MB
work_mem = 512MB

有关如何提高此功能的效率的任何提示?

4

1 回答 1

0

在 Richard Huxton 的提示之后,这是我使用的查询:

UPDATE tableA set rue_trouvee=t4.rue 
   FROM (SELECT id, rue 
       FROM (SELECT t1.id, t2.rue, similarity(t1.rue, t2.rue) as similarity, rank() 
             OVER (PARTITION BY t1.id ORDER BY similarity(t1.rue, t2.rue) DESC) 
             FROM tableA t1 JOIN tableB t2 
             ON (t1.cp = t2.code_post AND t1.rue % t2.rue) 
             WHERE t1.x is null AND t1.iso_pays='FR') t3 
       WHERE rank=1) t4 
   WHERE tableA.id=t4.id

我想这可以更优雅、更有效地解决,但至少这有效并在 5 小时后给了我想要的更新。

于 2013-07-19T13:14:16.010 回答