私のテストでは、は、すべてのであなたの質問に役立つかもしれないと思われます。他の索引タイプは、(I)LIKE/FTSベースの検索をスピードアップする可能性があります。
私は、クエリのすべては、以下の、彼らは照会されたときに「逆転」トライグラムインデックスを使用することを言及すべきである:表が(インデックス付けされて)文書が含まれている場合、そしてあなたのパラメータがクエリです。 (I)LIKE変種f.ex. 2〜3倍速くなります。
まず
select *
from musicians
where :input_string ilike '%' || firstname || '%'
or :input_string ilike '%' || lastname || '%'
or :input_string ilike '%' || instrument || '%'
は、FTSは素晴らしいアイデアに見えたが、私のテストでもランク付けずに、それはLIKE(I)よりも60〜100倍遅いことを示しています。
これらのクエリは、私がテストしてみましたバリアント。 (したがって、これらのメソッドで結果を後処理する必要がない場合でも、これらは価値がありません)。
select *
from musicians
where to_tsvector(:input_string) @@ (plainto_tsquery(firstname) || plainto_tsquery(lastname) || plainto_tsquery(lastname))
はしかし、
ORDER BY rank
はそれほどさらに遅くなることはありません:それは変LIKE(I)よりも70-120倍遅いです。
<%
と
%>
(PostgreSQLの9.6から入手可能):
select *
from musicians
where to_tsvector(:input_string) @@ (plainto_tsquery(firstname) || plainto_tsquery(lastname) || plainto_tsquery(lastname))
order by ts_rank(to_tsvector(:input_string), plainto_tsquery(firstname) || plainto_tsquery(lastname) || plainto_tsquery(lastname))
はその後、最後の努力のために、私は(かなり新しい)「という単語の類似度」トライグラムモジュールの演算子を試してみました。
select *
from musicians
where :input_string %> firstname
or :input_string %> lastname
or :input_string %> instrument
select *
from musicians
where firstname <% :input_string
or lastname <% :input_string
or instrument <% :input_string
これらは、(I)LIKE変異体よりも約50~70倍遅いFTSよりもやや速かった。
(一部作業)rextester:それはPostgreSQLの9.5に対して実行されるので、9.6演算子は、明らかに、ここで実行されません。
更新:フルワードマッチはあなたのための十分なされている場合は、実際にインデックスを使用できるようにするには、クエリを逆にすることができます。あなたは、クエリ「解析」する必要がありますけれども(別名「長い文字列を」。):
with long_string(ls) as (
values (:input_string)
),
words(word) as (
select s
from long_string, regexp_split_to_table(ls, '[^[:alnum:]]+') s
where s <> ''
)
select musicians.*
from musicians, words
where firstname ilike word
or lastname ilike word
or instrument ilike word
group by musicians.id
注:私はすべての完全な単語のためのクエリを解析されました。他にもいくつかのロジックを持たせることも、クライアント側で解析することもできます。それは(I)LIKE(ここでは、完全な単語の一致を探しているとして、我々は、とにかくそれらを必要としません)とトライグラムインデックスよりもはるかに高速であるよう
デフォルト、btree
指数は、ここに輝く:
with long_string(ls) as (
values (:input_string)
),
words(word) as (
select s
from long_string, regexp_split_to_table(lower(ls), '[^[:alnum:]]+') s
where s <> ''
)
select musicians.*
from musicians, words
where lower(firstname) = word
or lower(lastname) = word
or lower(instrument) = word
group by musicians.id
http://rextester.com/PSABJ6745
あなたもマッチ順で
sum((lower(firstname) = word)::int
+ (lower(lastname) = word)::int
+ (lower(instrument) = word)::int)
「長い文字列」に「ドラム」が含まれていて、「ドラム」の代わりに含まれている場合はどうなりますか? [全文検索](https://www.postgresql.org/docs/current/static/textsearch.html)は受け入れられますか? ([類似していますが、設定可能なランク付けシステム](https://www.postgresql.org/docs/current/static/textsearch-controls.html#TEXTSEARCH-RANKING)があります)。 – pozs
私はそれがうまくいくと思います - 偽陽性は後でフィルターにかけることができます - しかし、 "テキスト"がポストグレスの外にあるとき、全文検索はどのように動作しますか?多分私はそれがどのように機能するか誤解していますか? – user1051849
* postgres *の外で何を意味しますか?あなたの例では、 'lowercase_string'はpostgresの" inside "のようです:) - 明らかに、クエリパラメータ(クライアントに依存します)としてバインドするだけです。プリペアドステートメントでは、ほとんどのDBALでは 'ORDER BY ts_rank(to_tsvector(?)、plainto_tsquery(firstname)|| plainto_tsquery(lastname)|| ...) 'のように見えます。 – pozs