【问题标题】:Improve performance of postgresql query提高 postgresql 查询的性能
【发布时间】:2021-06-21 23:46:18
【问题描述】:

我的程序中的一个查询有问题。我有 2 个表:data_all_de 和employees_de。一般来说,我在 10 个国家/地区都有相同的情况,但以“DE”为例。

data_all_de 有 31 列,没有索引和 1 个主键 - id (int)。这张表大概有2M条记录,但是满足查询条件的记录大约有505K条。

employers_de 有 3 列(id int、employer_name varchar(255)、variations varchar[](255) - 数组、无主键、无索引。这里有 44K 条记录。

我的查询看起来:

UPDATE data_all_de
SET company_ok = (SELECT name 
                    FROM employers_de
                    WHERE employer_name = ANY(variations) LIMIT 1)
WHERE data_all_de.employer_name is not null 
AND data_all_de.company_ok is null 
AND data_all_de.row_status = 'N';"""

这需要 40 分钟到 60 分钟,具体取决于国家/地区。我尝试用 EXPLAIN 分析它们,所以这是 DE 的输出:

    "Update on data_all_de  (cost=0.00..3377618.96 rows=627019 width=1642)"
    "  ->  Seq Scan on data_all_de  (cost=0.00..3377618.96 rows=627019 width=1642)"
    "        Filter: ((employer_name IS NOT NULL) AND (company_ok IS NULL) AND (row_status = 'N'::bpchar))"
    "        SubPlan 1"
    "          ->  Limit  (cost=0.00..0.78 rows=1 width=25)"
    "                ->  Seq Scan on employers_de  (cost=0.00..908.06 rows=1169 width=25)"
    "                      Filter: (data_all_de.employer_name = ANY ((variations)::text[]))"
    "JIT:"
    "  Functions: 11"
    "  Options: Inlining true, Optimization true, Expressions true, Deforming true"

我该如何改进呢?使用索引?将此查询拆分为 2 个较小的查询并使用“临时”表?

一般情况下,employees_de 中的数据是不变的,但 data_all_de 中的数据每天都在变化,并且每天都会在向表中插入新数据后执行此查询。

此外,此查询同时针对 10 个国家/地区(10 对 data_all_xx + 雇主_xx)运行。

我将不胜感激。

【问题讨论】:

  • 你可能是employer_name = ANY(variations)。我认为您需要修复数据模型以提高效率——也就是说,使用索引优化数组引用相当棘手。

标签: sql postgresql optimization


【解决方案1】:

我建议修复employers_de 的结构,这样您就不会使用数组操作:

create table employers_de_normalized as
    select e.employee_name, u.variation
    from employers_de e cross join lateral
         unnest(de.variations) u(variation);

create index idx_employers_de_normalized_variation on employers_de_normalized(variation);

然后将查询的set部分写成:

SET company_ok = (SELECT edn.employer_name 
                  FROM employers_de_normalized edn
                  WHERE de.employer_name = edn.variation
                  LIMIT 1
                 )

这应该使用索引并且要快得多。请注意,LIMIT 1 对我来说仍然存在问题。您可以在创建临时表时使用DISTINCT ON 来解决此问题,因此variation 在表中是唯一的。

【讨论】:

  • 为什么现在查询计划的成本比以前高?我用您的 SQL 创建了表 'employers_de_normalized' 并将我以前的 SET 替换为 'SET company_ok = (SELECT edn.name FROM employees_de_normalized edn WHERE data_all_de.employer_name = edn.variation LIMIT 1)' 但现在我得到“更新 data_all_de (cost= 0.00..526137913.71 行=627019 宽度=1642)"。我用 1:1 对而不是数组(新表)理解你的想法,但是这个解释的结果对我来说是非常误解......在 SET 上使用“distinct on”我得到“data_all_de 的更新(成本=0.00..526148886.55行=627019 宽度=1642)'
  • @Bob 。 . .您是否创建了指定的索引?
  • 哦,我忘了 - 对不起这个愚蠢的错误。我现在创建了“Data_all_de 更新(成本=0.00..8188868.76 行=627019 宽度=1642)”,并带有不同的开启。为什么这个成本比我原来的版本高?
  • @Bob 。 . .您的版本中的计划说 employer_de 有 1,169 行。但是你的问题是44k。这可能与估计的差异有关。
  • 我发布了 44k,因为它取决于不同的国家,这是平均水平。在 DE 的情况下,我现在检查了一下,employees_de 中有 23.914 行,employees_de_normalized 中有 36.280 行。你知道为什么在 EXPLAIN 上我得到 1.169 行,而实际行数非常不同?
猜你喜欢
  • 2021-08-03
  • 2013-02-17
  • 2017-11-23
  • 2015-07-11
  • 2018-10-19
  • 2021-07-30
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多