【问题标题】:Finding out the total count of each tag in a data set找出数据集中每个标签的总数
【发布时间】:2014-09-10 07:31:26
【问题描述】:

我有一组Item-s,每个人都有一组Tag-s。我想要一个 DB SELECT,对于这些项目的一些(大)子集,返回该 Item 子集中每个 Tag 的总数。

有没有办法使用 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 表都很大(分别为数亿和数百万项),是否有任何特殊索引可以帮助提高效率?

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

【问题讨论】:

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


    【解决方案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 将运行顺序扫描。

    【讨论】:

      猜你喜欢
      • 2021-01-19
      • 1970-01-01
      • 2022-11-01
      • 2021-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-23
      相关资源
      最近更新 更多