SQL优化 - 字符串中的字数 - Postgresql

时间:2013-06-19 17:50:31

标签: sql postgresql optimization parallel-processing

我正在尝试使用Postgresql上字段中的单词计数来更新一个大表(大约1M行)。 此查询有效,并设置计算表token_countlongtext中的字词(令牌)的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行上完成它。 你会做些什么来优化它?有没有办法避免加入?

如何使用例如limitoffset将批处理拆分为块?

感谢您的任何提示,

Mulone

更新:我测量了array_split的性能,无论如何更新都会很慢。因此,解决方案可能包括并行化。如果我从psql运行不同的查询,则只有一个查询有效,其他查询等待它完成。如何并行更新?

4 个答案:

答案 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)

  1. 确保将myid编入索引,作为索引中的第一个字段。

  2. 首先考虑在DB外部执行此操作。很难说没有基准测试,但计数可能比选择+更新更昂贵;所以可能值得。

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

    • 运行一个简单的Perl脚本来计算。 Perl的100万行应该需要几分钟到1小时,具体取决于IO的速度。

    • 使用COPY将表复制回DB(可能进入临时表,然后从该临时表更新;或者更好的是截断主表,如果能够负担停机时间,直接COPY到它)。 / p>

  3. 对于您的方法,以及我的方法#2的最后一步,以5000行的批量更新token_count(例如,将rowcount设置为5000,并将更新循环添加where token_count IS NULL到查询< / p>