我目前正在设计一个 PostgreSQL 数据库,我需要在其中实现标记功能。本质上,我的数据库中许多表(7+)中的任何项目都可以通过键值标签进行标记,非常类似于 Azure 标签。
我正在考虑实现此功能的不同方法,但我对最佳方法感到困惑,因为这一定是许多数据模型中的常见问题:
使用 Django 的通用外键。
我正在考虑的一种方法是利用 Django 的通用外键功能来创建一个通用的“标签”表,该表可以引用数据库中的任何其他表。这允许灵活性并避免复杂的逻辑。但是,可能会存在一些缺点,例如性能影响或如果没有 Django 的 ORM,数据库就没有意义。
在单个表中手动实现,无需通用外键。
另一种选择是手动实现“Tags”表,而不依赖 Django 的通用外键。我将创建一个单独的表,可以引用数据库中的任何其他表,但不使用正式的外键。这需要在数据库或后端存储一些逻辑,维护起来更加复杂。
每个表都有单独的交叉引用标签表。
或者,我可以为数据库中需要标记的每个表创建一个单独的表(即
car_tags
、house_tags
、person_tags
)。这种方法将确保清晰的分离和潜在的更好的性能,但它可能会导致冗余并增加查询和维护的复杂性。
在每个表中添加
tags TEXT[]
数组列。
在每个需要标记的表中引入一个“tags”数组列,而不是维护一个通用的“Tags”表。这简化了查询,但可能会限制灵活性和可扩展性。
哪种方法最适合此用例?我更关心数据库的可维护性和可扩展性,而不是性能。如果这些不合适,您可以建议在 PostgreSQL 中实现灵活标记系统的任何最佳实践。
只是弱的、未强制/未保护的引用。
Tags
表将有另外两列,一列标识它所标记的 thing的类型,另一列保存该事物的唯一标识符。 无论有没有 Django ORM,理解这一点都不难。这实际上是 PostgreSQL 在内部管理某些事物的方式:
告诉您它列出的thing 的类型,
pg_class.oid
标识特定的事物。当您在系统视图或
information_schema
中查找内容时,它将过滤到
pg_class
中列出的特定类型的内容,并在oid
上加入它。
create table tag (
id bigint generated by default as identity primary key,
name text);
create table tag_anything (
tag_id bigint references tag(id),
other_thing_type text,
other_thing_id text);
create view cat_tagged as
select cat.*,array_agg(tag.name) as tags
from cat
join tag_anything ta
on ta.other_thing_type='cat'
and ta.other_thing_id=cat.id
join tag
on tag.id=ta.tag_id;
group by cat.id;
uuid
作为所有事物的 pk,使每个事物的每个标识符在类型上全局唯一且统一,从而简化了这一点。 您还需要实现自己的机制来处理
ON UPDATE
、ON DELETE
GenericForeignKey
的作用以及您可能尝试重新实现的内容,那么这只是每个事物一个表而已:上面示例中的 tag_anything
tag_cat
,失去了
thing_type
列并获得正确的外键引用,具有足够的类型。
您可以免费获得
on update
、
on delete
和一致性检查。
到处添加
text[]
或jsonb