【问题标题】:How to Increase Query Speed of Large Tables in Postgres如何提高 Postgres 中大表的查询速度
【发布时间】:2022-01-22 02:31:39
【问题描述】:

我在查询中使用了 2 个表:tableA 和 tableB。 TableA 的行数为 80568353,tableB 的行数为 101806780。它们都共享相同的 10 列(tableB 有额外的 4 列),包括 p_id。我的目标是有一个查询,它从 tableA 创建一个新表,其中 p_id 与 tableB 中的 p_id 不匹配。这是我的查询:

CREATE TABLE my_schema.tableC AS
    SELECT * FROM my_schema.tableA
    WHERE p_id NOT IN (SELECT DISTINCT p_id::int FROM my_schema.tableB)

这通宵运行,从未完成。我跑去EXPLAIN 看看为什么。结果如下:

 Gather  (cost=20252382.21..3330358576969.77 rows=40283932 width=89)
   Workers Planned: 7
   ->  Parallel Seq Scan on tableA  (cost=20251382.21..3330354547576.57 rows=5754847 width=89)
    Filter: (NOT (SubPlan 1))
    SubPlan 1
      ->  Materialize  (cost=20251382.21..20814813.52 rows=6107669 width=8)
            ->  Unique  (cost=20251382.21..20760416.17 rows=6107669 width=8)
                  ->  Sort  (cost=20251382.21..20505899.19 rows=101806792 width=8)
                        Sort Key: tableB.p_id
                        ->  Seq Scan on tableB  (cost=0.00..5079937.92 rows=101806792 width=8)

我是 PostgreSQL 新手,但 cost=20251382.21..3330354547576.57 似乎非常高。我尝试返回并运行以下命令来创建索引以加快速度:

CREATE INDEX IF NOT EXISTS a_p_int_idx ON my_schema.tableA (CAST(p_id as int));
CREATE INDEX IF NOT EXISTS b_p_int_idx ON my_schema.tableB (CAST(p_id as int));

这似乎没有帮助。我还在两张桌子上运行了VACUUM ANALYZE。没有得到改善。我在这里做错了什么;有什么方法可以提高速度并让它运行或实现我的目标的替代方法?注意:tableA 的 p_id 是 int,tableB 的 p_id 是双精度。会不会有影响?

更新:我无法让 EXPLAIN ANALYZE 完成,但我能够运行 EXPLAIN VERBOSE

Gather  (cost=20506959.93..3330368701110.81 rows=40283932 width=89)
Output: tableA.geoid, tableA.p_id, tableA.land_use_t, tableA.prop_ind_t, tableA.story_nbr, tableA.bld_units, tableA.censuspop, tableA.hu_pop, tableA.point_x, tableA.point_y
Workers Planned: 7
->  Parallel Seq Scan on my_schema.tableA  (cost=20505959.93..3330364671717.61 rows=5754847 width=89)
    Output: tableA.geoid, tableAs.p_id, tableA.land_use_t, tableA.prop_ind_t, tableA.story_nbr, tableA.bld_units, tableA.censuspop, tableA.hu_pop, tableA.point_x, tableA.point_y
    Filter: (NOT (SubPlan 1))
    SubPlan 1
      ->  Materialize  (cost=20505959.93..21069392.95 rows=6107669 width=4)
            Output: ((tableB.p_id)::integer)
            ->  Unique  (cost=20505959.93..21014995.61 rows=6107669 width=4)
                  Output: ((tableB.p_id)::integer)
                  ->  Sort  (cost=20505959.93..20760477.77 rows=101807136 width=4)
                        Output: ((tableB.p_id)::integer)
                        Sort Key: ((tableB.p_id)::integer)
                        ->  Seq Scan on my_schema.tableB  (cost=0.00..5334459.20 rows=101807136 width=4)
                              Output: (tableB.p_id)::integer

我也试过

EXPLAIN VERBOSE
SELECT * FROM my_schema.tableA a
WHERE NOT EXISTS(SELECT p_id FROM 
my_schema.tableB 
WHERE p_id::int = a.p_id)

测试NOT EXISTS 的建议,但成本相同(没有真正的改进)。

【问题讨论】:

  • 你能告诉我们 EXPLAIN(ANALYZE, VERBOSE, BUFFERS) 的结果吗?没有它,就不可能看到时间都花在了哪里。
  • 不需要子查询中的distinct
  • 注意:tableA 的 p_id 是 int,tableB 的 p_id 是双精度。那会影响它吗? (添加到问题中)
  • 顺便说一下,NOT EXISTS() 很可能比您现在使用的 NOT IN() 构造更快。
  • 如果您在两个表的选择中有相同的列,您可以尝试使用 EXCEPT 子句,例如: CREATE TABLE my_schema.tableC AS SELECT p_id FROM my_schema.tableA EXCEPT SELECT DISTINCT p_id::int FROM my_schema .tableB

标签: sql postgresql performance indexing


【解决方案1】:

在许多数据库中,命令NOT INNOT EXISTS 性能不佳,因为您可以使用left join 编写此查询,您将获得非常非常高的性能。例如:

SELECT * FROM my_schema.tableA aa 
left join my_schema.tableB bb on aa.p_id = bb.p_id 
WHERE 
    bb.id is null --here you must use one of the not null field of tableB (for example primary key of tableB)

并且您必须为两个表中的p_id 字段创建一个普通的btree index

【讨论】:

    猜你喜欢
    • 2012-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 2012-09-01
    • 1970-01-01
    相关资源
    最近更新 更多