我有一组Item
- s,每个都有一组Tag
- s。我想要一个DB SELECT,对于这些项目的某些(大)子集,它返回该Tag
子集中每个Item
的总数。
有没有办法使用PostgreSQL 9.3 / 9.4数组运算符?
我的计划B是有一个单独的表Tags
和多对多链接表Item_Tags
,然后执行:
CREATE TABLE "Tags" (
"Name" character varying,
id uuid NOT NULL,
CONSTRAINT id PRIMARY KEY (id)
);
CREATE TABLE "Items" (
id uuid NOT NULL,
data character varying,
CONSTRAINT "Items_pkey" PRIMARY KEY (id)
);
CREATE TABLE "Item_Tags" (
tag_id uuid,
item_id uuid,
id uuid NOT NULL,
CONSTRAINT "Item_Tags_pkey" PRIMARY KEY (id),
CONSTRAINT "Item_Tags_item_id_fkey" FOREIGN KEY (item_id)
REFERENCES "Items" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT "Item_Tags_tag_id_fkey" FOREIGN KEY (tag_id)
REFERENCES "Tags" (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
Select "Tags"."Name", count(*)
From "Tags"
Join "Item_Tags" on "Tags"."id" = "Item_Tags"."tag_id"
Join "Items" on "Items"."id" = "Item_Tags"."item_id"
Where "Items"."data" in ('a', 'b', 'c', 'd', 'e') -- replace with actual criteria
Group By "Tags"."Name"
有更好的方法吗?
假设Items
和Tags
表都很大(分别是数亿和数百万个),是否有任何特殊的索引可以帮助提高效率?
如果我想要所有标签的数量(没有过滤),我应该创建一个视图并使用它吗?
答案 0 :(得分:1)
您的B计划是一种优越的方法(例外情况适用)。但是你的实现看起来不太好。不要使用非描述性标识符,如“id”或“name”,不要使用双引号混合大小写标识符等。请使用“最佳实践”代码示例考虑此相关答案:
另外,如果您不需要,请不要使用UUID
列。数据类型bigint
(为您的pk列使用bigserial
!)可以轻松覆盖“数亿”行,并且在磁盘上更快更小。
使用干净的实现,(实质上更快)查询可能如下所示:
对于一小部分行:
SELECT tag_id, t.tag, c.ct
FROM (
SELECT it.tag_id, count(*) AS ct
FROM item i
JOIN item_tag it USING (item_id)
WHERE i.data = ANY ('{a,b,c,d,e}') -- ANY is shorter for a long list
GROUP BY 1
) c
JOIN tag t USING (tag_id);
对于所有标签(根本不加入表item
):
SELECT tag_id, t.tag, c.ct
FROM (
SELECT tag_id, count(*) AS ct
FROM item_tag
GROUP BY 1
) c
JOIN tag t USING (tag_id);
特别是对于很多行,在加入之前需要汇总:
特殊案例的特殊索引可能 - 您必须明确定义。特别是,partial indices 可能派上用场。
视图根本不会有助于提高性能。这只是一个“保存的查询” materialized view对于只读表非常有用,或者如果您不需要在每个结果中包含最新更改。 Postgres 9.3推出。 Expect further improvements from the upcoming Postgres 9.4.