5

我正在尝试使用 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,则只有一个查询有效,其他查询等待它完成。如何并行更新?

4

4 回答 4

11

你试过使用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)
于 2013-06-19T18:00:53.790 回答
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
    );
于 2013-06-19T18:12:06.677 回答
2

使用tsvectorts_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)
于 2017-03-10T07:49:25.950 回答
-2
  1. 确保myid被索引,成为索引中的第一个字段。

  2. 首先考虑在数据库之外执行此操作。没有基准很难说,但是计数可能比 select+update 成本更高;所以可能是值得的。

    • 使用 COPY 命令(Postgres 的 BCP 等效命令)将表数据有效地批量复制到文件中

    • 运行一个简单的 Perl 脚本来计数。对于 Perl,100 万行应该需要几分钟到 1 小时,这取决于你的 IO 有多慢。

    • 使用 COPY 将表复制回数据库(可能复制到临时表,然后从该临时表更新;或者如果您能承受停机时间,最好截断主表并直接复制到其中)。

  3. 对于您的方法和我的方法 #2 的最后一步,以 5000 行为单位更新 token_count(例如,将 rowcount 设置为 5000,然后循环添加where token_count IS NULL到查询中的更新

于 2013-06-19T17:59:02.897 回答