【发布时间】:2021-11-10 16:39:39
【问题描述】:
我有一个包含 94M 记录的日志表,并托管在 16GB 的 RAM、6CPU 和快速 SSD 上。
Log 表有多个字段,但查询使用三个主要字段运行,UserId(int)、DateStamp(timestamp) 和 Result(boolean)。
这些字段也有一个索引
create index "IX_Log_UserId_DateStampDate_Result"
on "Log" ("""UserId""", ("DateStamp"::date), """Result""");
我们将 DateStamp 转换为索引中的 Date,因为我们将 DateStamp 分组为 Date。
SQL
SELECT "Log"."UserId",
date("Log"."DateStamp") AS "Date",
count(*) AS "Conversions",
"Log"."Result"
FROM "Log"
GROUP BY "Log"."UserId", (date("Log"."DateStamp")), "Log"."Result"
执行计划(看起来好像没有在分组中使用索引。)
Group (cost=16701795.29..17867897.49 rows=93288176 width=9)
" Group Key: ""UserId"", (date(""DateStamp"")), ""Result"""
-> Sort (cost=16701795.29..16935015.73 rows=93288176 width=9)
" Sort Key: ""UserId"", (date(""DateStamp"")), ""Result"""
" -> Seq Scan on ""Log"" (cost=0.00..3100034.20 rows=93288176 width=9)"
问题是执行分组查询大约需要 4 分钟,在迁移到 PostgreSQL 之前,我们一直在 MS SQL 上运行相同的数据库,而 MS SQL 在同一台 PC 上执行该查询只需 10 秒。
其他 PostgreSQL 参数
work_mem=32000kb (changing this do not makes any difference)
shared_buffers=200MB
effective_cache_size=12GB
已编辑
我还添加了一个扩展的解释计划。
GroupAggregate (cost=16701795.29..19033999.69 rows=93288176 width=17) (actual time=278258.047..516820.577 rows=331187 loops=1)
Group Key: ""UserId"", (date(""DateStamp"")), ""Result""
Buffers: shared hit=31437 read=1902506, temp read=216860 written=217003
I/O Timings: read=9319.798
-> Sort (cost=16701795.29..16935015.73 rows=93288176 width=9) (actual time=278258.028..403513.564 rows=93288174 loops=1)
Sort Key: ""UserId"", (date(""DateStamp"")), ""Result"""
Sort Method: external merge Disk: 1734880kB
Buffers: shared hit=31437 read=1902506, temp read=216860 written=217003
I/O Timings: read=9319.798
-> Seq Scan on ""Log"" (cost=0.00..3100034.20 rows=93288176 width=9) (actual time=0.021..137339.749 rows=93288174 loops=1)
Buffers: shared hit=31426 read=1902506
I/O Timings: read=9319.798
Planning Time: 0.700 ms
Execution Time: 517321.399 ms
【问题讨论】:
-
没关系,但有什么理由不放弃
GROUP BY子句而改为使用SELECT DISTINCT ...? -
@Tim Biegeleisen 我不确定你的意思,但是分组和区分是两个不同的东西。我需要按日期、用户 ID 和结果(真或假)分组。
-
...在这种情况下它们是相同的
-
@a_horse_with_no_name 但在此查询中,只需要一个 SORT,因为这本质上是一个 DISTINCT。我们需要查看执行计划并从 SQL Server 中“借用”一些技巧
-
你真的应该摆脱那些可怕的引用标识符。在名称中包含双引号 (
""UserId"") 更糟糕
标签: sql postgresql