2012-04-16 107 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