我正在尝试在我的数据库中的字段中搜索相同的文本以查找实时搜索框。
SELECT DISTINCT u.id, u.username FROM
users AS u, user_invoice AS ui, user_roles AS ur, roles AS r WHERE
u.id = ur.user_id AND
ur.role_id = r.id AND
r.name = 'teacher' AND
(
ui.user_id = u.id AND
CAST(ui.invoice AS TEXT) = 'searchterm'
)
此查询搜索发票表并正确且非常快速地返回结果。
SELECT DISTINCT u.id, u.username FROM
users AS u, user_invoice AS ui, user_roles AS ur, roles AS r WHERE
u.id = ur.user_id AND
ur.role_id = r.id AND
r.name = 'teacher' AND
(u.username like '%searchterm%')
此查询搜索匹配的用户名并且返回速度也非常快。
但是当我像这样将两者结合起来时:
SELECT DISTINCT u.id, u.username FROM
users AS u, user_invoice AS ui, user_roles AS ur, roles AS r WHERE
u.id = ur.user_id AND
ur.role_id = r.id AND
r.name = 'teacher' AND
(
u.username like '%searchterm%' OR
(
ui.user_id = u.id AND
CAST(ui.invoice AS TEXT) = 'searchterm'
)
)
它会返回正确的结果,但要花费将近一分钟的时间。我做错了什么?
编辑:解释我的查询:
首先: http://explain.depesz.com/s/PvS
第二个: http://explain.depesz.com/s/D5c
综合: http://explain.depesz.com/s/Dhf
因复制类型转换错误而编辑。
最佳答案
以下是我在主应用程序中解决此问题的方法。
我有一个我希望用户能够搜索的主要实体。称它为客户
。此实体在 1:n contact
(电话、电子邮件等)表中有关联的详细记录。
我定义了一个 View customer_quicksearch
,它计算一个快速搜索键 - 一个 text
字段,其中包含客户的 contact
记录的串联直接使用一些 customer
字段。
我已将触发器添加到 customer
和 contact
customer_summary
表。 customer
触发器在 customer
中插入一行时向 customer_summary
添加一条记录,并在 customer
中删除该行记录被删除。他们通过从“customer_quicksearch”中SELECT
更新的快速搜索键来更新customer_summary
。我可以为此使用 SQL 函数而不是 View ,但发现 View 更有用也更快。使用 View 可以更快地为所有客户计算快速搜索键,例如,在批量插入或更新之后。
CREATE VIEW customer_quicksearch AS
SELECT
customer.id AS customer_id, array_to_string(ARRAY[
customer.code,
customer.name,
string_agg(array_to_string(ARRAY[
contact.email::text,contact.altemail::text, contact.mobile_phone, contact.work_phone, contact.home_phone, contact.fax
],'|'),'|')
], '|') AS quicksearch_key
FROM customer
LEFT OUTER JOIN contact ON (customer.id = contact.customer_id)
GROUP BY customer.id;
和触发器之一:
CREATE OR REPLACE FUNCTION customer_summary_update_for_contact() RETURNS trigger AS $$
DECLARE
_customer_id integer;
BEGIN
-- When a contact is added/removed/changed we have to regenerate the customer search key
IF tg_op = 'INSERT' OR tg_op = 'UPDATE' THEN
_customer_id = NEW.customer_id;
ELSE
_customer_id = OLD.customer_id;
END IF;
UPDATE customer_summary
SET quicksearch_key = (SELECT quicksearch_key FROM customer_quicksearch WHERE customer_id = _customer_id)
WHERE customer_id = _customer_id;
RETURN NULL;
END;
$$
LANGUAGE 'plpgsql'
SET search_path = 'public';
CREATE TRIGGER customer_summary_update_for_contact_trg AFTER INSERT OR UPDATE OR DELETE ON contact
FOR EACH ROW EXECUTE PROCEDURE customer_summary_update_for_contact();
您还需要一个customer
触发器来处理客户的insert
、update
和delete
,维护customer_summary
相应地记录该客户。
customer_summary
表包含包含 quicksearch_key
的记录,它是字段的管道连接,例如:
'1800MA|1800 MAKE IT BUILDERS|info@1800makeit.example.com|1234 5678|0499 999 999'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
[from customer record] [from 1st contact record] [from another contact record]
这是使用简单的 LIKE
模式搜索的。如果我进行前缀搜索,我可以在其上添加一个 text_pattern_ops
索引以提高性能,但由于我主要在没有左 anchor 或右 anchor 的情况下进行搜索 - LIKE '%search%'
- 没有任何好处。
关于postgresql - 使用 Postgres 在多个字段中搜索一个术语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12905351/