【问题标题】:Effectively query on column that includes a substring有效查询包含子字符串的列
【发布时间】:2012-04-16 03:45:45
【问题描述】:

给定一个值类似于/123/12/34/56/5/ 的字符串列,查询所有包含给定数字的记录(例如12)的最佳方法是什么?

我想到的解决方案是:

SELECT id FROM things WHERE things.path LIKE '%/12/%'

但 AFAIK 由于前导 %,此查询无法在列上使用索引。

一定有更好的东西。这是什么?

使用 PostgreSQL,但更喜欢也适用于其他数据库的解决方案。

【问题讨论】:

  • 最好不要多值字段:)
  • 我可以使用带有路径的附加表'thing_paths'。然后加入它并查询它~select DISTINCT things.id from things inner join thing_paths on thing_path.thing_id = things.id WHERE thing.path LIKE '/12/%'。但在这个阶段,这比我理想中想做的要多。

标签: sql postgresql indexing


【解决方案1】:

如果您愿意将该列转换为整数数组,例如:

'/123/12/34/56/5/' becomes ARRAY[123,12,34,56,5]

所以path_arrINTEGER[] 类型的列,那么您可以在该列上创建 GIN 索引:

CREATE INDEX ON things USING gin(path_arr);

对包含 12 的所有项目的查询则变为:

SELECT * FROM things WHERE ARRAY[12] <@ path_arr;

哪个会使用索引。在我的测试中(有一百万行),我得到如下计划:

EXPLAIN SELECT * FROM things WHERE ARRAY[12]  <@ path_arr;
                                      QUERY PLAN
----------------------------------------------------------------------------------------
 Bitmap Heap Scan on things  (cost=5915.75..9216.99 rows=1000 width=92)
   Recheck Cond: (path_arr <@ '{12}'::integer[])
   ->  Bitmap Index Scan on things_path_arr_idx  (cost=0.00..5915.50 rows=1000 width=0)
         Index Cond: ('{12}'::integer[] <@ path_arr)
(4 rows)

【讨论】:

  • 谢谢。那是另一种选择。但 AFAIK 在技术上与 Erwin 建议的 LIKE + GIN 索引相同,只是表达方式不同。
  • 这是另一个 GIN 索引。但它更接近实际数据。原则上索引会更有效,因为它不会记录包含“27/”和“1/2”等的项目。
  • Edmund,我接受 Erwin 的回答只是因为它更简单(还不需要更改任何代码)。但我希望我能接受 2 个答案,因为您的解决方案更优雅。
  • 在实用主义和优雅之间经常存在权衡。而且列表索引的语法没有帮助,所以我可能也选择了 Erwin 的答案(tbh)。感谢您的评论。
【解决方案2】:

在 PostgreSQL 9.1 中,您可以利用 pg_trgm module 并用它构建 GIN 索引。

CREATE EXTENSION pg_trgm; -- once per database

CREATE INDEX things_path_trgm_gin_idx ON things USING gin (path gin_trgm_ops);

你的LIKE 表达式可以使用这个索引,即使它不是左锚的。

详见demo by depesz here

如果你可以,将其标准化。

【讨论】:

  • 谢谢。很高兴知道。但是写入性能要慢得多。
  • RE 标准化。该列仅用于几乎一两个地方,尚不确定标准化是否值得。必须考虑更多。
  • RE 规范化:规范化的形式可能会快得多。
猜你喜欢
  • 2011-06-23
  • 1970-01-01
  • 2011-05-14
  • 2015-07-16
  • 2015-04-19
相关资源
最近更新 更多