【问题标题】:How to index variable character column for pattern matching in Postgres?如何为 Postgres 中的模式匹配索引变量字符列?
【发布时间】:2020-04-17 10:26:01
【问题描述】:

Postgres 版本:9.5.19

我有下表包含域:

CREATE TABLE sites (
  id SERIAL PRIMARY KEY,
  domain character varying(255),
);

-- Indices -------------------------------------------------------

CREATE UNIQUE INDEX sites_pkey ON sites(id int4_ops);
CREATE INDEX index_sites_on_domain ON sites(domain text_ops);
id | domain
---| -----------
1  | www.abc.com
2  | alpha.net
3  | catfood.xyz
4  | example.org
5  | un.gov
6  | xyz.com
.  | .......

表中的记录总数接近 100 万条,运行模式匹配查询轻松需要 20 多秒:

SELECT * from sites where domain LIKE '%abc.com%

我在domain 上有一个正常的btree 索引,但上面的查询没有使用它。 EXPLAIN 显示顺序扫描。

如何索引此列以使查询得到充分优化?

【问题讨论】:

  • Like '%xxx%' 不使用 btree 索引。就像 'xxx%' 一样。考虑使用 pg_trgm,如下所述:postgresql.org/docs/9.5/pgtrgm.html
  • 您的表是命名为“sites”,还是命名为“domains”?
  • 该查询对我来说很容易在半秒内完成(针对站点,而不是域),没有 1,572,864 行的索引。 '%un%' 太短,无法从三元组索引中受益,所以如果这是一个有代表性的查询,它不会对你有多大好处。
  • 在查询中使用正确的表名更新了问题。我同意 %un% 太短,但是,我们使用的实际通配符模式比这长,主要是实际域,例如www.abc.com、www.longls.com 等等等等。
  • 我同意 jjanes:20 秒对一百万行进行全表扫描似乎相当慢。但如果您的搜索模式较长,则三元组索引可能会有所帮助

标签: postgresql indexing pattern-matching query-optimization sql-like


【解决方案1】:

首先在域部分上创建一个表达式索引,例如将'www.abc.com' 转换为数组'{www,abc,com}'

CREATE INDEX index_on_domain ON sites USING GIN (regexp_split_to_array(domain, '\.'));

然后运行稍作修改的查询。

SELECT *
FROM sites
WHERE regexp_split_to_array(domain, '\.') @> '{abc,com}'
  AND domain LIKE '%abc.com%

它肯定比你原来的查询更难看,但它会完成这项工作。

where 子句的第一个条件将使用 GIN 索引通过检查域部分是否包含与您的查询相同的部分来显着减少结果集。第二个将充当验证条件,以确保 'abc' 紧接在 'com' 之前,但只会针对与第一个索引条件匹配的行运行。如果从 v9.5 开始频繁更新站点表,请改用 GIST(或 GIN with fastupdate),标准 GIN 索引更适合大多数只读用例,而 GIST 在定期更新的表/索引上具有更好的性能。

可以使用三元组,但我认为它们对于非结构化文本更有用。另一方面,域具有结构,其中各部分具有不同的(和原子的)含义。这当然取决于您的用例,但根据您的描述,我假设您也没有在寻找像 'sample.xyzabc.com' 这样的结果。如果你是,那么三元组实际上可能是要走的路,因为你的查询确实是非结构化的。如果您实际上是在寻找完整的域部分,那么拆分域并通过独立的内聚部分进行搜索可能会给您带来更清晰的结果。

此外,如果您的查询由于代码不可修改或由不易修改的库生成而无法更改,则在使用开放式 LIKE 通配符模式时,您可能不得不接受顺序扫描性能不佳,如此处所示。

【讨论】:

    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    • 2020-04-06
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    相关资源
    最近更新 更多