web-dev-qa-db-ja.com

Postgresは列に格納された正規表現をインデックス化できますか?

列にvarcharsとして格納されている正規表現を持っています。これを入力と照合する必要があります。たとえば、テーブルには以下が含まれます。

| field |     value     |
|-------|---------------|
| email | .*@domain.com |

そしてクエリは次のようになります:

SELECT *
FROM table
WHERE field = 'email'
  AND '[email protected]' ~* value

これはかなりばかげていますが、約2年間は十分に機能しましたが、私は最初に認めます。これで、テーブルは最大1万行になり、クエリは3秒程度にまで減速しました。私はすでにより合理的な戦略に私たちを移動させたので、この質問は純粋に学術的なものです。

この設定を保持していた場合、ルックアップを効率的にする方法はありますか?私はvarchar_pattern_opsの兄弟を期待していましたが、このクエリはそれが解決するものの逆です。


アイデアを下にして、ここに完全なテーブル、クエリ、および説明があります。

+------------+-----------------------------+------------------------------------------------------------+
| Column     | Type                        | Modifiers                                                  |
|------------+-----------------------------+------------------------------------------------------------|
| id         | integer                     | not null default nextval('table_id_seq'::regclass)         |
| field      | character varying(255)      | not null                                                   |
| value      | character varying(1000)     | not null                                                   |
| comment    | text                        |                                                            |
+------------+-----------------------------+------------------------------------------------------------+
Indexes:
    "table_pkey" PRIMARY KEY, btree (id)
    "index_table_on_field_and_value" UNIQUE, btree (field, value)


EXPLAIN ANALYZE
SELECT *
FROM table
WHERE (
    (field = 'contact_email' AND '[email protected]' ~* value)
 OR (field = 'phone'         AND value = '1234567890')
 OR (field = 'unique_id'     AND value = 'abcdef')
);

Seq Scan on table (cost=0.00..613.08 rows=58 width=1) (actual time=744.371..744.371 rows=0 loops=1)
Filter: ((((field)::text = 'contact_email'::text) AND ('[email protected]'::text ~* (value)::text))
      OR (((field)::text = 'phone'::text) AND ((value)::text = '01234567890'::text))              
      OR (((field)::text = 'unique_id'::text) AND ((value)::text = 'abcdef'::text)))             
Rows Removed by Filter: 11643
Total runtime: 744.395 ms
4
Kristján

ショートバージョン:いいえ。 (少なくともPostgreSQLでは)パターン列にインデックスを付ける実用的な方法がないため、「このプレーンテキストがこれらのパターンのいずれかと一致する」クエリを高速化する方法でプレーンテキスト入力と照合できます。

PostgreSQLは、パターンの一致を「理解した」特別なカスタムインデックスタイプを必要とします。私はそれを実装することがどれほど実用的であるか、またそのようなインデックスからどれだけ得ることができるかわかりません。ないので、質問はやや学問的です。

6
Craig Ringer