【发布时间】: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