Ce que vous demandez peut être fait. Pour avoir un exemple pratique (avec seulement deux tables), vous pourriez avoir:
CREATE TABLE users
(
user_id SERIAL PRIMARY KEY,
username text
) ;
-- Index to find usernames
CREATE INDEX idx_users_username_full_text
ON users
USING GIN (to_tsvector('english', username)) ;
CREATE TABLE topics
(
topic_id SERIAL PRIMARY KEY,
topic text
) ;
-- Index to find topics
CREATE INDEX idx_topics_topic_full_text
ON topics
USING GIN (to_tsvector('english', topic)) ;
Voir docs PostgreSQL. sur Controlling Text Search pour une explication de to_tsvector
.
... alimenter les tables
INSERT INTO users
(username)
VALUES
('Alice Cooper'),
('Boo Geldorf'),
('Carol Burnet'),
('Daniel Dafoe') ;
INSERT INTO topics
(topic)
VALUES
('Full text search'),
('Fear of void'),
('Alice in Wonderland essays') ;
... créer une vue qui combine les valeurs des deux tables
CREATE VIEW search_items AS
SELECT
text 'users' AS origin_table, user_id AS id, to_tsvector('english', username) AS searchable_element
FROM
users
UNION ALL
SELECT
text 'topics' AS origin_table, topic_id AS id, to_tsvector('english', topic) AS searchable_item
FROM
topics ;
Nous recherche ce point de vue:
SELECT
*
FROM
search_items
WHERE
plainto_tsquery('english', 'alice') @@ searchable_element
.. et obtenez la réponse suivante (vous devriez ignorer le searchable_element
). Vous êtes principalement intéressé par les origin_table
et id
.
origin_table | id | searchable_element
:----------- | -: | :--------------------------------
users | 1 | 'alic':1 'cooper':2
topics | 3 | 'alic':1 'essay':4 'wonderland':3
Voir Parsing requêtes pour une explication de plainto_tsquery
fonction, et aussi @@
operator.
Pour réaliser des index sûrs sont utilisés:
EXPLAIN ANALYZE
SELECT
*
FROM
search_items
WHERE
plainto_tsquery('english', 'alice') @@ searchable_element
| QUERY PLAN |
| :----------------------------------------------------------------------------------------------------------------------------------------- |
| Append (cost=12.05..49.04 rows=12 width=68) (actual time=0.017..0.031 rows=2 loops=1) |
| -> Bitmap Heap Scan on users (cost=12.05..24.52 rows=6 width=68) (actual time=0.017..0.018 rows=1 loops=1) |
| Recheck Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, username)) |
| Heap Blocks: exact=1 |
| -> Bitmap Index Scan on idx_users_username_full_text (cost=0.00..12.05 rows=6 width=0) (actual time=0.005..0.005 rows=1 loops=1) |
| Index Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, username)) |
| -> Bitmap Heap Scan on topics (cost=12.05..24.52 rows=6 width=68) (actual time=0.012..0.012 rows=1 loops=1) |
| Recheck Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, topic)) |
| Heap Blocks: exact=1 |
| -> Bitmap Index Scan on idx_topics_topic_full_text (cost=0.00..12.05 rows=6 width=0) (actual time=0.002..0.002 rows=1 loops=1) |
| Index Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, topic)) |
| Planning time: 0.098 ms |
| Execution time: 0.055 ms |
Les index sont vraiment utilisés (voir Bitmap Index Scan on idx_topics_topic_full_text
et Bitmap Index Scan on idx_users_username_full_text
).
Vous pouvez vérifier tout à dbfiddle here
REMARQUE: 'english'
est le text search configuration choisi d'indexer et de requête. Choisissez le bon pour votre cas. Vous pouvez créer le vôtre si les existants ne répondent pas à vos besoins.
Vous pouvez faire une telle chose. Assurez-vous que les colonnes (ou expressions) nécessaires sur les tables d'origine ont les bons index. Testez également les plans d'exécution produits lorsque vous interrogez la vue, pour vous assurer qu'ils affichent l'utilisation de l'index. Sinon, ça va marcher, mais vraiment très lentement. Alternativement, vous pouvez avoir une * vue matérialisée *, et avoir les index directement dessus; et assurez-vous de le mettre à jour assez fréquemment. – joanolo