找出数据集中每个标记的总数

时间:2014-07-19 05:55:54

标签: sql postgresql database-design many-to-many aggregate-functions

我有一组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"

有更好的方法吗?

假设ItemsTags表都很大(分别是数亿和数百万个),是否有任何特殊的索引可以帮助提高效率?

如果我想要所有标签的数量(没有过滤),我应该创建一个视图并使用它吗?

1 个答案:

答案 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.

  • 如果您希望计算所有标记索引根本不会有助于提高性能,因为Postgres将在涉及大部分或全部表时运行顺序扫描。