2012-04-16 56 views
2

鉴于类似于/123/12/34/56/5/值的字符串列,什么是查询所有记录,包括在给定数量12为例)的最佳方式列有效查询?上包括子

从我头顶上的解决方案是:

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

但据我所知这个查询可以对列,由于领先%不使用索引。

必须有更好的东西。它是什么?

使用PostgreSQL,但宁愿该解决方案可以跨越其他数据库。

+2

这将是最好不要有一个多值字段:) – 2012-04-16 03:49:15

+0

我可以去与附加表“thing_paths”在它的路径。然后加入并查询它〜'从事物内部连接thing_paths中选择DISTINCT things.id on thing_path.thing_id = things.id WHERE thing.path LIKE'/ 12 /%''。但在这个阶段,它超出了我理想的状态。 – 2012-04-16 03:56:04

回答

3

在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

正常化如果你可以,但。

+0

谢谢。这很好。尽管如此,写入性能却显着降低。 – 2012-04-16 03:58:49

+0

RE正常化。本专栏仅用于一两个地方,不确定标准化是否值得。必须多想一想。 – 2012-04-16 04:09:36

+0

RE规范化:规范化的形式可能会快得多。 – kgrittn 2012-04-16 09:30:20

4

如果你感到快乐开启该列到一个整数数组,如:

'/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) 
+0

谢谢。这是另一种选择。但是AFAIK在技术上与Erwin建议的'LIKE' + GIN索引相同,只是表达方式不同而已。 – 2012-04-16 07:03:04

+0

这是另一个GIN索引。但它与实际数据更接近。原则上索引会更有效率,因为它不会记录包含“27 /”和“1/2”等的项目等。 – Edmund 2012-04-16 07:06:47

+0

埃德蒙,我接受埃尔温的答案只是因为它更简单(不必更改任何代码呢)。但我希望我能接受2个答案,因为你的解决方案更加优雅。 – 2012-04-18 03:04:25