两个表之间的文本字段中最匹配:如何改进plpgsql函数

时间:2013-07-18 08:16:50

标签: sql postgresql postgresql-9.1

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

A包含来自不同国家/地区的数据,因此函数参数包含相应的表名称,但也包含我处理的国家/地区数据表(B)中相关字段的名称。

各表中的相关字段为:

A

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

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

1 个答案:

答案 0 :(得分: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小时后给了我想要的更新。