我正在尝试使用Postgresql上字段中的单词计数来更新一个大表(大约1M行)。
此查询有效,并设置计算表token_count
中longtext
中的字词(令牌)的my_table
字段:
UPDATE my_table mt SET token_count =
(select count(token) from
(select unnest(regexp_matches(t.longtext, E'\\w+','g')) as token
from my_table as t where mt.myid = t.myid)
as tokens);
myid
是表格的主键。
\\w+
是必要的,因为我想数字,忽略特殊字符。
例如,A test . ; )
将返回5,基于空格的计数,而2是正确的值。
问题是它非常慢,2天不足以在1M行上完成它。
你会做些什么来优化它?有没有办法避免加入?
如何使用例如limit
和offset
将批处理拆分为块?
感谢您的任何提示,
Mulone
更新:我测量了array_split的性能,无论如何更新都会很慢。因此,解决方案可能包括并行化。如果我从psql
运行不同的查询,则只有一个查询有效,其他查询等待它完成。如何并行更新?
答案 0 :(得分:7)
您是否尝试过使用array_length
?
UPDATE my_table mt
SET token_count = array_length(regexp_split_to_array(trim(longtext), E'\\W+','g'), 1)
http://www.postgresql.org/docs/current/static/functions-array.html
# select array_length(regexp_split_to_array(trim(' some long text '), E'\\W+'), 1);
array_length
--------------
3
(1 row)
答案 1 :(得分:2)
UPDATE my_table
SET token_count = array_length(regexp_split_to_array(longtext, E'\\s+'), 1)
或没有相关性的原始查询
UPDATE my_table
SET token_count = (
select count(*)
from (select unnest(regexp_matches(longtext, E'\\w+','g'))) s
);
答案 2 :(得分:2)
tsvector
and ts_stat
获取tsvector列的统计信息
SELECT *
FROM ts_stat($$
SELECT to_tsvector(t.longtext)
FROM my_table AS t
$$);
没有可以尝试的样本数据,但它应该有效。
CREATE TEMP TABLE my_table
AS
SELECT $$A paragraph (from the Ancient Greek παράγραφος paragraphos, "to write beside" or "written beside") is a self-contained unit of a discourse in writing dealing with a particular point or idea. A paragraph consists of one or more sentences.$$::text AS longtext;
SELECT *
FROM ts_stat($$
SELECT to_tsvector(t.longtext)
FROM my_table AS t
$$);
word | ndoc | nentry
--------------+------+--------
παράγραφος | 1 | 1
written | 1 | 1
write | 1 | 2
unit | 1 | 1
sentenc | 1 | 1
self-contain | 1 | 1
self | 1 | 1
point | 1 | 1
particular | 1 | 1
paragrapho | 1 | 1
paragraph | 1 | 2
one | 1 | 1
idea | 1 | 1
greek | 1 | 1
discours | 1 | 1
deal | 1 | 1
contain | 1 | 1
consist | 1 | 1
besid | 1 | 2
ancient | 1 | 1
(20 rows)
答案 3 :(得分:-1)
确保将myid
编入索引,作为索引中的第一个字段。
首先考虑在DB外部执行此操作。很难说没有基准测试,但计数可能比选择+更新更昂贵;所以可能值得。
使用COPY命令(Postgres的BCP等效值)将表数据有效地批量复制到文件中
运行一个简单的Perl脚本来计算。 Perl的100万行应该需要几分钟到1小时,具体取决于IO的速度。
使用COPY将表复制回DB(可能进入临时表,然后从该临时表更新;或者更好的是截断主表,如果能够负担停机时间,直接COPY到它)。 / p>
对于您的方法,以及我的方法#2的最后一步,以5000行的批量更新token_count(例如,将rowcount设置为5000,并将更新循环添加where token_count IS NULL
到查询< / p>