postgresql - 进一步加快后缀通配符搜索

标签 postgresql

I recently asked a question关于加速后缀通配 rune 本查找,例如 Pg 中的 SELECT a, b, c FROM t WHERE a LIKE 'abcde%'。最后,通过实现以下索引,我可以将每个查询的时间缩短到 200 毫秒到 800 毫秒。

CREATE INDEX idxa ON t (Lower(a) varchar_pattern_ops);

如果可能的话,我现在有兴趣将查询速度提高一个数量级;可能在 200-800 微秒之间。这能做到吗?

整个表格大约有 1 GB 的原始文本(约 800 万多行),并且可以做得更小,因此很容易装入内存。我可以在 Pg 之上实现一个缓存,一个会随时间播种的缓存吗?也许是 memcached 或其他东西。由于大多数缓存都有精确的键查找,我该如何从缓存中进行通配符搜索?

顺便说一句,作为一个信息点,我确实在 Mongodb 中加载了整个表,虽然我对精确搜索 a = 'abcdefg' 进行了非常快速的查找,但上面的 Mongodb 通配符搜索实际上是不如 Postgres。

最佳答案

你还可以再挤出一些。

首先,我通常建议使用数据类型 text而不是 varchar .所以text_pattern_ops而不是 varchar_pattern_ops .不过这不会影响性能。


接下来,由于您的列最多有 100 个字符,但您只使用前 n(20?)个字符,因此 lower(left(a, 20) 的索引会小得多。而不是 lower(a)正如我在 answer to your prequel question 中所建议的那样.

索引搜索本身执行相同,但服务器必须访问磁盘或 RAM 中的更多页面。每个 RAM 或磁盘页面将容纳更少的行,因此每次查找都必须访问更多的页面。此外,页面会更快地从您的缓存中删除,等等。这对于像您这样的大表尤其重要。将可以搜索的字母范围限制为所需的最小值。这给你留下了类似的东西:

CREATE INDEX t_a_lower_left_idx ON t (lower(left(a, 20)) text_pattern_ops);

此外,您还可以使用特殊运算符 ~>=~~<~在你的查询中,就像我在 answer I linked to 中展示的那样:

SELECT * FROM tbl WHERE lower(a) ~>=~ 'abcde' AND lower(a) ~<~ ('abcdf')

请注意第二个表达式中的“f”而不是“e”。问题是:如何根据语言环境“C”获得“下一个”字符?

SELECT chr(ascii('é')+1));

所以你可以:

SELECT * FROM tbl WHERE lower(a) ~>=~ 'abcde'
                    AND lower(a) ~<~ ('abcd' || chr(ascii('e')+1))

我用一个包含 50 万行的自然表进行了测试。产生 650 行的搜索词第一次查询花费 4 毫秒,第二次查询花费 3 毫秒。这非常很大程度上取决于找到的行数。此处仅产生 1 行的搜索词需要 0.044 毫秒。


因此,限制搜索词的最小长度以禁止无用的查询,这些查询无论如何都会产生太多行。至少 3 或 4 个字符。


接下来可以cluster你的 table 是这样的:

CLUSTER tbl USING t_a_lower_left_idx

在那之后,我的测试用例用了 2.5 毫秒而不是 3 毫秒。


当然,所有basic advice for performance optimization适用。


如果以上还不够,您可能需要考虑创建一个 tablespace在 ramdisk 或 tmpfs 分区 (Linux) 上并在那里创建索引,甚至将整个表放在那里。我相信您了解 volatile 介质对数据库的安全隐患。只有在您能够承受丢失所有数据的情况下才这样做。

CREATE INDEX t_a_lower_left_idx ON t (lower(left(a, 20)) text_pattern_ops)
TABLESPACE indexspace;

如果您的数据库设置正确并且您的机器有足够的 RAM 并且表被大量读取,则标准缓存算法可能会自动提供大部分性能增益,而您不会因此获得太多。

关于postgresql - 进一步加快后缀通配符搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9267079/

相关文章:

php - postgresql全文搜索中的问题,包含单引号

c# - 我可以将 Parallel.For 与 sql 命令一起使用吗?

postgresql - 尽管连接字符串,Postgres 超时 20-30 秒?

sql - 返回所有使用特定枚举的表

postgresql - 在 plpgsql 中识别 jsonb null 的最佳实践

ruby-on-rails - 通过 DATABASE_URL 检查数据库状态

SQL 查询 : Iterate over values in table and use them in subquery

python - 插入枚举列的 Postgres 数组时,SQLAlchemy 引发错误

Postgresql - 用于保存文件的动态命名

javascript - sequelize 中的关联未按预期工作