【发布时间】:2023-02-24 01:45:51
【问题描述】:
问题
我们有一个关系表,用于存储用户活动。像下面这样的查询77秒!
FROM "site_activity"
WHERE
(
NOT "site_activity"."is_deleted"
AND "site_activity"."user_id" = 68812389
AND NOT (
"site_activity"."kind" IN (
'updated',
'duplicated',
'reapplied'
)
)
AND NOT (
"site_activity"."content_type_id" = 14
AND "site_activity"."kind" = 'created'
)
)
ORDER BY
"site_activity"."created_at" DESC,
"site_activity"."id" DESC
LIMIT 9;
查询计划看起来像这样
QUERY PLAN
--------------------------------------------------------------------------------------------
Limit
(cost=17750.72..27225.75 rows=9 width=16)
(actual time=199501.336..199501.338 rows=9 loops=1)
Output: id, created_at
Buffers: shared hit=4502362 read=693523 written=37273
I/O Timings: read=190288.205 write=446.870
-> Incremental Sort
(cost=17750.72..2003433582.97 rows=1902974 width=16)
(actual time=199501.335..199501.336 rows=9 loops=1)
Output: id, created_at
Sort Key: site_activity.created_at DESC, site_activity.id DESC
Presorted Key: site_activity.created_at
Full-sort Groups: 1 Sort Method: quicksort Average Memory: 25kB Peak Memory: 25kB
Buffers: shared hit=4502362 read=693523 written=37273
I/O Timings: read=190288.205 write=446.870
-> Index Scan Backward using site_activity_created_at_company_id_idx on public.site_activity
(cost=0.58..2003345645.30 rows=1902974 width=16)
(actual time=198971.283..199501.285 rows=10 loops=1)
Output: id, created_at
Filter: (
(NOT site_activity.is_deleted) AND (site_activity.user_id = 68812389)
AND ((site_activity.kind)::text <> ALL ('{updated,duplicated,reapplied}'::text[]))
AND ((site_activity.content_type_id <> 14) OR ((site_activity.kind)::text <> 'created'::text))
)
Rows Removed by Filter: 14735308
Buffers: shared hit=4502353 read=693523 written=37273
I/O Timings: read=190288.205 write=446.870
Settings: effective_cache_size = '261200880kB',
effective_io_concurrency = '400',
jit = 'off',
max_parallel_workers = '24',
random_page_cost = '1.5',
work_mem = '64MB'
Planning:
Buffers: shared hit=344
Planning Time: 6.429 ms
Execution Time: 199501.365 ms
(22 rows)
Time: 199691.997 ms (03:19.692)
表格事实
-
它包含的内容略多于40 亿行.
-
表结构是
Table "public.site_activity" Column | Type | Collation | Nullable | Default ----------------+--------------------------+-----------+----------+---------------------------------------------- id | bigint | | not null | nextval('site_activity_id_seq'::regclass) created_at | timestamp with time zone | | not null | modified_at | timestamp with time zone | | not null | is_deleted | boolean | | not null | object_id | bigint | | not null | kind | character varying(32) | | not null | context | text | | not null | company_id | integer | | not null | content_type_id | integer | | not null | user_id | integer | | | Indexes: "site_activity_pkey" PRIMARY KEY, btree (id) "site_activity_modified_at_idx" btree (modified_at) "site_activity_company_id_idx" btree (company_id) "site_activity_created_at_company_id_idx" btree (created_at, company_id) "site_activity_object_id_idx" btree (object_id) "site_activity_content_type_id_idx" btree (content_type_id) "site_activity_kind_idx" btree (kind) "site_activity_kind_idx1" btree (kind varchar_pattern_ops) "site_activity_user_id_idx" btree (user_id) Foreign-key constraints: "site_activity_company_id_fk_site_company_id" FOREIGN KEY (company_id) REFERENCES site_company(id) DEFERRABLE INITIALLY DEFERRED "site_activity_content_type_id_fk_django_co" FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED "site_activity_user_id_fk_site_user_id" FOREIGN KEY (user_id) REFERENCES site_user(id) DEFERRABLE INITIALLY DEFERREDA。
kind实际上是一个enum。其中大约有 100 个值。b.
content_type_id有大约 80 个值。 -
这是值的分布,
A。
context实际上是最大 8Mb 大小的 JSON。A。 3
content_type_id值保持92%的行A。 3
kind消费75%行。A。
kind和content_type_id的组合创建了 460 个值。其中,2 组合包含 65% 的行,我们始终在查询中排除它们。 -
副本实例的类型为
db.r5.12xlarge。24核心,48岁vCPU,384GB内存,存储类型IO1.问题
- 如果表增长到1000亿?在目前的预测中,这可能会在未来 3-5 年内发生。
- NoSQL 是一个好的解决方案吗?请注意,我们不是仅使用 id 或 kind 访问文档。
笔记
- 我提供的事实可能会使解决方案偏向于在同一主机中进行复制,然后在多个主机上进行分片。但如果有其他解决方案可以保持到 1000 亿大关,我们应该很好。
- 我们不必使用 AWS。但首选.
【问题讨论】:
-
性能将直接关系到硬件规格/cpus、并行查询的能力以及您如何调整查询/索引表/分区数据
-
您可以考虑像 clickhouse 这样的内存数据库。虽然不是关系数据库,但它与 Postgres 兼容
-
发布解释计划将在调整该查询方面获得更直接的响应。
-
您能否分享您的 SQL 语句的 EXPLAIN(ANALYZE, VERBOSE, BUFFERS, SETTINGS) 的结果? (以纯文本形式,作为您问题的更新)
-
@FrankHeikens 我已经添加了您要求的解释!
标签: sql database postgresql amazon-web-services amazon-rds