【问题标题】:Postgres optimisation of multicolumn indexes with text column带有文本列的多列索引的 Postgres 优化
【发布时间】:2020-05-24 11:14:41
【问题描述】:

我有一个关于Postgres中索引优化的问题,我在网上没有找到太多帮助,我一直在努力通过测试自己得到答案。

我有这张桌子

CREATE TABLE "public"."crawls" (
    "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
    "parent_id" uuid,
    "group_id" timestamp,
    "url" varchar(2083) NOT NULL,
    "done" boolean;
    PRIMARY KEY ("id")
);
CREATE UNIQUE INDEX "parentid_groupid_url" ON "public"."urls" USING BTREE ("parent_id","group_id","url");

这是一个 URL 存储,用于计算每个父级和每个组唯一的 URL 的完整列表。我只需要在这个索引上完全匹配。 这意味着只要 group_id 不同,parent_id 就可以多次同时具有相同的 URL。

该表包含数亿个URL,主要用于写入,UNIQUE索引用于去重。

  UPDATE crawls
  SET
    done = TRUE
  WHERE
    url = $1 AND
    parent_id = $2 AND
    group_id = $3

INSERT 

INTO crawls (
      url,
      parent_id,
      group_id
    ) VALUES
      ('long urls', uuid, date)
    ON CONFLICT parentid_groupid_url DO NOTHING

目前性能还可以,但可能会更好,并且由于 url 列,索引大小大于表本身。

我想知道如何改进尺寸和/或性能? (如果可能,两个)

我考虑过使用一个新列对 URL 进行散列 (md5, sha1) 并在索引中使用它而不是 URL,以便长度一致、更小并且对于 Postgres 可能更快,但我没有找到任何帮助。 由于哈希的“随机性”,我不确定它是否有效,并且由于在我的产品上构建索引的大小和时间,我很难测试这个假设。

我在网上找到的参考资料:

谢谢,

【问题讨论】:

  • 什么是 parent_id ?也许REFERENCING (public.crawls.id)? (自我参考)
  • 这是一个外部引用,它在真实数据库中没有被命名为喜欢它,但我想简化问题的架构(我失败了啊啊)。

标签: database postgresql indexing database-performance


【解决方案1】:

我考虑过使用一个新列对 URL 进行哈希 (md5, sha1) 并在索引中使用它而不是 URL,以便长度一致、更小并且对于 Postgres 可能更快

create index on crawls (parent_id,group_id,md5(url));

这将自动强制唯一性(并且还禁止在完整 URL 上真正不同的 md5 冲突 - 但在没有恶意的情况下发生这种情况的可能性很小)。但是,它不会自动用于快速查找,您必须调整查询以允许使用它:

WHERE
  md5(url) = md5($1) AND
  parent_id = $2 AND
  group_id = $3

您可以使用比十六进制更短的表示来节省更多空间:

create index on crawls (parent_id,group_id,decode(md5(url),'hex'));

但这会让它使用起来更加麻烦。

由于哈希的“随机性”,我不确定它是否有效

这完全取决于您的使用模式和数据分布。如果你经常访问一系列具有相同 parent_id 和 group_id 的记录以及相邻的 url,并且具有相同 parent_id 和 group_id 的记录数量很大,那么对 url 进行哈希处理会降低缓存的有效性。

由于在我的产品上构建索引的大小和时间,我很难测试这个假设。

没有测试环境就是双手被绑在背后。

【讨论】:

  • 您会建议在实际产品用例中使用这种模式吗?我很惊讶 postgres 不是“更好”的精确匹配优化。与潜在收益相比,所需的最小变化似乎在很大程度上是可以接受的。 > 并且 parent_id 和 group_id 相同的记录数很大,从 100 到 500k 不等。我不确定 btree 索引如何与文本列(以及 md5)一起使用,它会尝试用长文本拆分树还是最终会在 parent->group 之后扫描整个树?
  • 从稳定性/错误的角度来看,我在生产中使用它没有问题。但是我希望看到它确实可以提高性能的证据,否则有什么意义呢?我不明白你在问什么“用长文本拆分树”。
猜你喜欢
  • 2023-03-04
  • 2015-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多