【问题标题】:Postgres index is ignored on large tablePostgres 索引在大表上被忽略
【发布时间】:2021-10-14 09:29:17
【问题描述】:

我有一个非常简单的查询,它在 Postgres 11.12 上需要超过 10 分钟才能完成:

SELECT COUNT(r.*) as active_jobs 
    FROM project_raw_data r 
        INNER JOIN jobs j ON j.id = r.processing_job_id 
    WHERE r.ind_requires_processing = True AND
          r.processing_error = False AND
          r.processing_job_id IS NOT NULL AND
          j.finished IS NULL AND
          j.started IS NOT NULL;

project_raw_data 表有 ~50M 行,大小约为 500GB(其中有一些更大的元数据,此查询中涉及的列都是 booleantimezone),jobs 表有~1M 行。

我在project_raw_data 表上应用了以下索引:

CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_project_raw_data_processing_active ON  
    project_raw_data 
    USING btree (ind_requires_processing, processing_error, processing_job_id);

还有jobs 表上的这个:

CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_studio_jobs_active ON 
    jobs 
    USING btree (id) WHERE ((finished IS NULL) AND (started IS NOT NULL));

如果我查看 PgAnalyze,索引应该已经是该查询的最佳索引:

所以我有点不太了解为什么这需要 10 分钟并从磁盘读取 70GB (!)(查看分析时)。

这是EXPLAIN ANALYZE 的输出:

Finalize Aggregate  (cost=9860168.44..9860168.45 rows=1 width=8) (actual time=690627.757..690628.919 rows=1 loops=1)
  ->  Gather  (cost=9860168.23..9860168.44 rows=2 width=8) (actual time=690625.874..690628.908 rows=3 loops=1)
        Workers Planned: 2
        Workers Launched: 2
        ->  Partial Aggregate  (cost=9859168.23..9859168.24 rows=1 width=8) (actual time=690623.471..690623.475 rows=1 loops=3)
              ->  Hash Join  (cost=97.43..9859165.28 rows=1180 width=1135) (actual time=690623.464..690623.467 rows=0 loops=3)
                    Hash Cond: (r.processing_job_id = j.id)
                    ->  Parallel Seq Scan on project_raw_data r  (cost=0.00..9845488.13 rows=5173208 width=1139) (actual time=690623.462..690623.463 rows=0 loops=3)
                          Filter: (ind_requires_processing AND (NOT processing_error) AND (processing_job_id IS NOT NULL))
                          Rows Removed by Filter: 16661364
                    ->  Hash  (cost=93.42..93.42 rows=321 width=4) (never executed)
                          ->  Index Only Scan using idx_studio_jobs_active on jobs j  (cost=0.27..93.42 rows=321 width=4) (never executed)
                                Heap Fetches: 0
Planning Time: 2.207 ms
Execution Time: 690629.645 ms

我们看到project_raw_data 表上的索引被完全跳过。但为什么呢?

【问题讨论】:

  • 使用count(*) 有什么改变吗?或者至少count(r.ind_requires_processing)。该步骤的预期行数与实际行数之间存在巨大差异。尝试analyze project_raw_data ;vacuum analyze project_raw_data ; 更新统计信息
  • @a_horse_with_no_name 哇,实际上在本地表上运行analyze 使它使用索引......现在将在我们的生产数据库上运行它,看看是否有区别。我们在数据库上启用了 autovacuum,所以没想到会需要这个。希望这确实可以解决问题。
  • 你的表有主键吗?他们有FK关系吗?这些是否受到约束/索引的支持?这些都应该在在非关键属性上添加任何额外索引之前定义。
  • @wildplasser,是的,两个表之间存在 PK 和 FK 关系。它们都有索引,每一列都应该被现有索引覆盖,如 PgAnalyze 屏幕截图所示(如果有帮助,可以显示表上的所有索引)。
  • 对不起,我不看截图。 DDL 更容易阅读。顺便说一句:你知道r.processing_job_id IS NOT NULL 条件是多余的吗?

标签: postgresql


【解决方案1】:

@a_horse_with_no_name 在 cmets 中建议在桌子上运行 vacuum analyze 就成功了。查询现在完全使用索引,并在 100 毫秒内完成。而是。

【讨论】:

    猜你喜欢
    • 2020-12-08
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    • 2016-05-25
    相关资源
    最近更新 更多