检索优化
根据 dataset_id
对 max_kb_paragraph
表进行分区
要根据 dataset_id
对 max_kb_paragraph
表进行分区,可以使用 PostgreSQL 的 分区表 功能。根据 dataset_id
的数据分布情况,可以选择 哈希分区、列表分区 或 范围分区。以下是使用 哈希分区 和 列表分区 的两种实现方式。
1. 使用哈希分区
哈希分区适用于 dataset_id
分布较为均匀且没有特定分组需求的情况。以下是具体步骤:
步骤 1:创建分区表
首先,创建一个分区表,并指定按 dataset_id
进行哈希分区。例如,使用 4 个分区:
DROP TABLE IF EXISTS max_kb_paragraph;
CREATE TABLE max_kb_paragraph (
id BIGINT PRIMARY KEY,
source_id BIGINT NOT NULL,
source_type VARCHAR NOT NULL,
content VARCHAR NOT NULL,
title VARCHAR NOT NULL,
status VARCHAR NOT NULL,
hit_num INT NOT NULL,
is_active BOOLEAN NOT NULL,
embedding VECTOR NOT NULL, -- 使用 pgvector 类型
meta JSONB NOT NULL,
dataset_id BIGINT NOT NULL,
document_id BIGINT NOT NULL,
paragraph_id BIGINT,
search_vector TSVECTOR,
creator VARCHAR(64) DEFAULT '',
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) DEFAULT '',
update_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted SMALLINT DEFAULT 0,
tenant_id BIGINT NOT NULL DEFAULT 0
) PARTITION BY HASH (dataset_id);
步骤 2:创建分区
接下来,创建具体的分区表。例如,创建 4 个分区:
CREATE TABLE max_kb_paragraph_p0 PARTITION OF max_kb_paragraph
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE max_kb_paragraph_p1 PARTITION OF max_kb_paragraph
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE max_kb_paragraph_p2 PARTITION OF max_kb_paragraph
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE max_kb_paragraph_p3 PARTITION OF max_kb_paragraph
FOR VALUES WITH (MODULUS 4, REMAINDER 3);
2. 使用列表分区
如果 dataset_id
有特定的分组需求或数量较少,可以使用列表分区。以下是具体步骤:
步骤 1:创建分区表
创建一个按 dataset_id
进行列表分区的表:
DROP TABLE IF EXISTS max_kb_paragraph;
CREATE TABLE max_kb_paragraph (
id BIGINT PRIMARY KEY,
source_id BIGINT NOT NULL,
source_type VARCHAR NOT NULL,
content VARCHAR NOT NULL,
title VARCHAR NOT NULL,
status VARCHAR NOT NULL,
hit_num INT NOT NULL,
is_active BOOLEAN NOT NULL,
embedding VECTOR NOT NULL, -- 使用 pgvector 类型
meta JSONB NOT NULL,
dataset_id BIGINT NOT NULL,
document_id BIGINT NOT NULL,
paragraph_id BIGINT,
search_vector TSVECTOR,
creator VARCHAR(64) DEFAULT '',
create_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updater VARCHAR(64) DEFAULT '',
update_time TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted SMALLINT DEFAULT 0,
tenant_id BIGINT NOT NULL DEFAULT 0
) PARTITION BY LIST (dataset_id);
步骤 2:创建分区
假设有特定的 dataset_id
值,例如 1, 2, 3, 4
,可以为每个值创建一个分区:
CREATE TABLE max_kb_paragraph_dataset1 PARTITION OF max_kb_paragraph
FOR VALUES IN (1);
CREATE TABLE max_kb_paragraph_dataset2 PARTITION OF max_kb_paragraph
FOR VALUES IN (2);
CREATE TABLE max_kb_paragraph_dataset3 PARTITION OF max_kb_paragraph
FOR VALUES IN (3);
CREATE TABLE max_kb_paragraph_dataset4 PARTITION OF max_kb_paragraph
FOR VALUES IN (4);
对于未列出的 dataset_id
,可以创建一个默认分区:
CREATE TABLE max_kb_paragraph_default PARTITION OF max_kb_paragraph
DEFAULT;
选择合适的分区策略
- 哈希分区:适用于
dataset_id
分布均匀且不需要按特定值进行查询优化的情况。分区数量需要根据实际数据量和查询性能需求进行调整。 - 列表分区:适用于
dataset_id
值较少且已知的情况,可以按特定值进行优化,但当dataset_id
数量较多或动态变化时,维护成本较高。
注意事项
- 索引和约束:在分区表上创建索引和约束时,需要在每个分区上单独创建,或者使用分区约束排除。
- 查询优化:确保查询中包含
dataset_id
以利用分区裁剪(partition pruning)提升性能。 - 维护分区:根据数据增长情况,定期添加新的分区以适应新的
dataset_id
值。
通过上述步骤,您可以根据 dataset_id
对 max_kb_paragraph
表进行有效的分区,从而提升查询性能和数据管理的灵活性。
查询
1. 使用列表分区时,查询是针对主表还是针对子表进行的?
查询目标:主表
查询主表:在 PostgreSQL 中,无论使用何种分区策略(列表分区、哈希分区、范围分区等),所有的查询都是针对**主表(父表)**发起的。主表本身不存储数据,而是作为分区的入口,负责将查询路由到相应的子分区表。
自动分区裁剪(Partition Pruning):当查询中包含分区键(在您的例子中是
dataset_id
)时,PostgreSQL 会自动识别并只访问相关的子分区表,从而提高查询性能。例如:SELECT * FROM max_kb_paragraph WHERE dataset_id = 2;
上述查询会自动路由到
max_kb_paragraph_dataset2
分区,而不需要扫描其他分区。查询不包含分区键:如果查询中不包含分区键,PostgreSQL 可能需要扫描所有相关的子分区,这可能会影响性能。因此,尽量在查询中包含分区键以利用分区裁剪的优势。
总结:无论是插入、更新还是查询操作,您都只需要针对主表执行操作,PostgreSQL 会根据分区策略自动处理具体的子表。