我正在尝试使用 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
?
感谢您的任何提示,
穆隆
更新:我测量了array_split的性能,无论如何更新都会很慢。因此,也许解决方案将包括并行化。如果我从
psql
运行不同的查询,则只有一个查询有效,其他查询则等待它完成。如何并行更新?
您尝试过使用
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)
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
);
tsvector
和 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)
regexp_count()
:
=> select regexp_count('Foo, bar baz! ', '\w+');
regexp_count
--------------
3
确保
myid
已建立索引,是索引中的第一个字段。首先考虑在数据库外部执行此操作。没有基准测试很难说,但是计数可能比 select+update 成本更高;所以可能值得。
使用 COPY 命令(Postgres 的 BCP 等效命令)将表数据高效地批量复制到文件中
运行一个简单的 Perl 脚本来计数。对于 Perl,100 万行应该需要几分钟到 1 小时,具体取决于您的 IO 有多慢。
使用 COPY 将表复制回数据库(可能复制到临时表中,然后从该临时表进行更新;或者更好的是截断主表并直接 COPY 到其中(如果您可以承受停机时间)。
对于您的方法以及我的方法 #2 的最后一步,以 5000 行为一批更新 token_count(例如,将 rowcount 设置为 5000,然后循环更新,将
where token_count IS NULL
添加到查询中