【问题标题】:Postgresql Query 10x Slower After Migration from EC2 to RDS从 EC2 迁移到 RDS 后 Postgresql 查询速度降低 10 倍
【发布时间】:2021-07-16 09:05:41
【问题描述】:

我们将我们的 postgresql 数据库从 EC2(在 Docker 上运行的 pg 12.1)迁移到 RDS(pg 12.6)。然后我们注意到一些查询变得非常慢(慢了 10 倍)

这是我们的查询之一

SELECT cp."FirstName" ,
       cp."LastName" ,
       cp."DealerGroupId" ,
       count(*) AS "DuplicateCount"
FROM "sc_CustomerProfiles" cp
WHERE (cp."FirstName" IS NOT NULL
       OR cp."LastName" IS NOT NULL)
  AND cp."UpdatedDate" > '2020-07-01'
  AND EXISTS
    (SELECT 1
     FROM "sc_CustomerProfiles" scp
     WHERE scp."FirstName" = cp."FirstName"
       AND cp."LastName" = scp."LastName"
       AND cp."DealerGroupId" = scp."DealerGroupId"
       AND scp."ProfileId" < 0 )
GROUP BY cp."FirstName" ,
         cp."LastName" ,
         cp."DealerGroupId"
HAVING count(*) > 1

在 EC2 上的旧数据库上运行 EXPLAIN ANALYZE 会得到以下结果

Finalize GroupAggregate  (cost=818304.54..922603.67 rows=196075 width=61) (actual time=1679.259..1931.629 rows=623 loops=1)
  Group Key: cp."FirstName", cp."LastName", cp."DealerGroupId"
  Filter: (count(*) > 1)
  Rows Removed by Filter: 2257
  ->  Gather Merge  (cost=818304.54..906894.61 rows=668500 width=61) (actual time=1678.763..1934.877 rows=3290 loops=1)
        Workers Planned: 2
        Workers Launched: 2
        ->  Partial GroupAggregate  (cost=817304.52..828733.10 rows=334250 width=61) (actual time=1637.652..1886.456 rows=1097 loops=3)
              Group Key: cp."FirstName", cp."LastName", cp."DealerGroupId"
              ->  Merge Semi Join  (cost=817304.52..822048.10 rows=334250 width=53) (actual time=1637.597..1886.015 rows=1212 loops=3)
                    Merge Cond: (((cp."FirstName")::text = (scp."FirstName")::text) AND ((cp."LastName")::text = (scp."LastName")::text) AND (cp."DealerGroupId" = scp."DealerGroupId"))
                    ->  Sort  (cost=564987.54..565957.09 rows=387821 width=53) (actual time=1632.503..1841.309 rows=284808 loops=3)
                          Sort Key: cp."FirstName", cp."LastName", cp."DealerGroupId"
                          Sort Method: external merge  Disk: 18248kB
                          Worker 0:  Sort Method: external merge  Disk: 18720kB
                          Worker 1:  Sort Method: external merge  Disk: 18720kB
                          ->  Parallel Seq Scan on "sc_CustomerProfiles" cp  (cost=0.00..515729.99 rows=387821 width=53) (actual time=575.396..1171.259 rows=284808 loops=3)
                                Filter: ((("FirstName" IS NOT NULL) OR ("LastName" IS NOT NULL)) AND ("UpdatedDate" > '2020-07-01 00:00:00+07'::timestamp with time zone))
                                Rows Removed by Filter: 2613490
                    ->  Sort  (cost=252316.98..252533.20 rows=86489 width=53) (actual time=4.940..5.162 rows=2937 loops=3)
                          Sort Key: scp."FirstName", scp."LastName", scp."DealerGroupId"
                          Sort Method: quicksort  Memory: 440kB
                          Worker 0:  Sort Method: quicksort  Memory: 440kB
                          Worker 1:  Sort Method: quicksort  Memory: 440kB
                          ->  Index Scan using "sc_CustomerProfiles_ProfileId" on "sc_CustomerProfiles" scp  (cost=0.43..242267.28 rows=86489 width=53) (actual time=0.018..1.700 rows=3055 loops=3)
                                Index Cond: ("ProfileId" < 0)
Planning Time: 1.337 ms
JIT:
  Functions: 79
  Options: Inlining true, Optimization true, Expressions true, Deforming true
  Timing: Generation 16.630 ms, Inlining 216.395 ms, Optimization 990.256 ms, Emission 518.330 ms, Total 1741.611 ms
Execution Time: 1992.259 ms

在 RDS 上的新数据库上运行时,会给出这个结果

Finalize GroupAggregate  (cost=744995.34..848665.34 rows=195480 width=61) (actual time=144257.571..194501.899 rows=621 loops=1)
  Group Key: cp."FirstName", cp."LastName", cp."DealerGroupId"
  Filter: (count(*) > 1)
  Rows Removed by Filter: 2261
  ->  Gather Merge  (cost=744995.34..833031.15 rows=664296 width=61) (actual time=144214.280..194498.590 rows=3190 loops=1)
        Workers Planned: 2
        Workers Launched: 2
        ->  Partial GroupAggregate  (cost=743995.31..755354.88 rows=332148 width=61) (actual time=139429.298..187940.480 rows=1063 loops=3)
              Group Key: cp."FirstName", cp."LastName", cp."DealerGroupId"
              ->  Merge Semi Join  (cost=743995.31..748711.92 rows=332148 width=53) (actual time=139405.473..187938.320 rows=1212 loops=3)
                    Merge Cond: (((cp."FirstName")::text = (scp."FirstName")::text) AND ((cp."LastName")::text = (scp."LastName")::text) AND (cp."DealerGroupId" = scp."DealerGroupId"))
                    ->  Sort  (cost=493373.41..494335.55 rows=384857 width=53) (actual time=138424.282..182706.702 rows=285254 loops=3)
                          Sort Key: cp."FirstName", cp."LastName", cp."DealerGroupId"
                          Sort Method: external merge  Disk: 19464kB
                          Worker 0:  Sort Method: external merge  Disk: 17672kB
                          Worker 1:  Sort Method: external merge  Disk: 18616kB
                          ->  Parallel Seq Scan on "sc_CustomerProfiles" cp  (cost=0.00..444513.80 rows=384857 width=53) (actual time=0.048..1509.801 rows=285255 loops=3)
                                Filter: ((("FirstName" IS NOT NULL) OR ("LastName" IS NOT NULL)) AND ("UpdatedDate" > '2020-07-01 00:00:00+07'::timestamp with time zone))
                                Rows Removed by Filter: 2613405
                    ->  Sort  (cost=250621.90..250838.81 rows=86762 width=53) (actual time=977.557..978.400 rows=2940 loops=3)
                          Sort Key: scp."FirstName", scp."LastName", scp."DealerGroupId"
                          Sort Method: quicksort  Memory: 441kB
                          Worker 0:  Sort Method: quicksort  Memory: 441kB
                          Worker 1:  Sort Method: quicksort  Memory: 441kB
                          ->  Index Scan using "sc_CustomerProfiles_ProfileId" on "sc_CustomerProfiles" scp  (cost=0.43..240537.35 rows=86762 width=53) (actual time=0.079..3.373 rows=3057 loops=3)
                                Index Cond: ("ProfileId" < 0)
Planning Time: 31.569 ms
Execution Time: 194505.100 ms

我注意到“扫描”部分的持续时间相似,但“排序”部分相距甚远。实例规格不一样,但我没有看到高 CPU 或内存利用率。这个问题的根本原因是什么,或者我应该如何调查这个问题?

解决方案

原来根本原因是 glibc 排序功能 (https://sourceware.org/bugzilla/show_bug.cgi?id=18441) 中仅针对泰语的错误。这在 EC2 上工作的原因是我们使用的是 postgres alpine docker 镜像,它使用 musl 而不是 glibc。

由于我们实际上不需要在泰语中对列进行排序,因此将 LC_COLLATE 更改为“C”确实可以解决问题。请注意,如果需要,我们也可以使用 ICU 排序规则。

【问题讨论】:

  • 我错过了慢的这一部分,JIT: Functions: 79 Options: Inlining true, Optimization true, Expressions true, Deforming true
  • 慢的不输出JIT部分。不知道是RDS没有配置还是什么?
  • 好像没有配置,所以没有优化。
  • 我试过启用JIT,没用
  • WHERE scp."FirstName" = cp."FirstName" AND cp."LastName" = scp."LastName" 您有基于文本列的 FK->PK 关系?真的吗? (顺便说一句:您的预期与观察到的行数差异太大恕我直言)

标签: sql postgresql amazon-web-services amazon-rds


【解决方案1】:

差异可能是写入和读取对 300000 行进行排序所需的临时文件时的 I/O 速度。

为了确定,将参数track_io_timing更改为on并使用EXPLAIN (ANALYZE, BUFFERS)。这也会显示 I/O 时间。

为避免临时文件,您可以增加 work_mem(尝试 100MB 左右),这应该会大大提高性能。

这个索引也可能是有益的:

CREATE INDEX ON "sc_CustomerProfiles" ("UpdatedDate")
   WHERE "FirstName" IS NOT NULL OR "LastName" IS NOT NULL;

(如果"FirstName""LastName" 通常不为NULL,则可以省略WHERE 子句。)

【讨论】:

  • 我也是这么想的,但我注意到应该在内存中完成的快速排序部分也慢了很多。你知道为什么吗?
  • 是的。也许您的 CPU 不足?
  • 我确实检查了 CPU 利用率,但看起来还不错
  • @hikky36 “看起来不错”是什么意思? CPU基本上是空闲的?它们已被此查询完全使用,但如果此查询未运行,它们将处于空闲状态?
  • 非空闲,但 CPU 利用率未超过 50%
【解决方案2】:

原来根本原因是 glibc 排序功能 (https://sourceware.org/bugzilla/show_bug.cgi?id=18441) 中仅针对泰语的错误。这在 EC2 上工作的原因是我们使用的是 postgres alpine docker 镜像,它使用 musl 而不是 glibc。

由于我们实际上不需要在泰语中对列进行排序,因此将 LC_COLLATE 更改为“C”确实可以解决问题。请注意,如果需要,我们也可以使用 ICU 排序规则。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-21
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 2011-01-02
    • 1970-01-01
    相关资源
    最近更新 更多