【问题标题】:SQL Query slow intermittently in postgresSQL Query 在 postgres 中间歇性变慢
【发布时间】:2015-12-24 22:27:03
【问题描述】:

运行以下查询时,有时需要 15 秒,有时需要 90 分钟。是什么导致了如此大的差异?

INSERT INTO missing_products 
SELECT table_name, 
   product_id 
FROM   products 
WHERE  table_name = 'xxxxxxxxx' 
   AND product_id NOT IN (SELECT id 
                               FROM new_products);

我已尝试对此进行解释,但我唯一能看到的是关于新产品的index only scan。我也重写了这个查询,改为使用左连接并插入右侧为 NULL 的行,但这会导致同样的时间问题。

我有以下表格,其结构类似于以下内容。

产品

id bigint not null,
product_id text not null,
table_name text not null,
primary key (id),
unique index (product_id)

新产品

id text not null,
title text not null,
primary key, btree (id)

缺少的产品

table_name text not null,
product_id text not null,
primary key (table_name, product_id)

解释 - 这在 where 子句中有一个额外的字段,但应该提供一个好主意。耗时 22 秒。

 Insert on missing_products  (cost=5184.80..82764.35 rows=207206 width=38) (actual time=22466.525..22466.525 rows=0 loops=1)
   ->  Seq Scan on products  (cost=5184.80..82764.35 rows=207206 width=38) (actual time=0.055..836.217 rows=411150 loops=1)
         Filter: ((active > (-30)) AND (NOT (hashed SubPlan 1)) AND (feed = 'xxxxxxxx'::text))
         Rows Removed by Filter: 77436
         SubPlan 1
           ->  Index Only Scan using new_products_pkey on new_products  (cost=0.39..5184.74 rows=23 width=10) (actual time=0.027..0.027 rows=0 loops=1)
                 Heap Fetches: 0
 Planning time: 0.220 ms
 Execution time: 22466.596 ms

【问题讨论】:

  • 请提供EXPLAIN ANALYZE 输出,这将帮助我们了解是否有任何触发器可能导致缓慢

标签: sql postgresql


【解决方案1】:

显然查看EXPLAIN ANALYZE 的输出,SELECT 几乎不需要 800 毫秒,大部分时间,几乎 22 秒 花费在 INSERTING 行中。

此外,您的 new_products 表的统计数据似乎不准确,因为它预测 23 行而实际行只有 0,现在看来该计划是正确的,这可能是灾难性的,具体取决于 new_products 表的情况在整个应用程序中使用,如果自动分析没有启动,我首先会定期 ANALYZE 表,并监控一天内的性能

【讨论】:

  • 良好的观察。我想看看性能不佳的实际时间(90 分钟)会很有趣,看看时间是否按比例花费在相同的地方,或者select 语句是否突然成为瓶颈。
  • 确实,我怀疑 90m 的缓慢是由于不正确的统计数据
  • 如果是统计数据不正确的问题,我该如何解决这个问题而不是定期运行 ANALYZE?
  • 您可以减少给定表格的autovacuum_analyze_threshold,更多信息:postgresql.org/docs/9.0/static/…
  • 谢谢,我也更改了查询以解释分析,因此我可以查看查询计划是否会在 90 分钟内发生变化。
【解决方案2】:

我会尝试两件事:

  1. 尝试在products.table_name 上添加索引,目前您似乎没有。

  2. 尝试重写查询以使用not exists 子句而不是not in。有时,数据库可以通过这种方式更有效地执行查询:

使用not exists查询:

INSERT INTO missing_products (table_name, product_id)
SELECT p.table_name, p.product_id 
  FROM products p
 WHERE p.table_name = 'xxxxxxxxx' 
   AND NOT EXISTS (SELECT null
                     FROM new_products n
                    WHERE n.id = p.product_id)

【讨论】:

  • 哇,这很好地改变了查询计划,并且更多地依赖于顺序扫描。现在只是测试,确保它返回相同的结果。
猜你喜欢
  • 2018-09-24
  • 1970-01-01
  • 1970-01-01
  • 2018-10-24
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-01
相关资源
最近更新 更多