我正在尝试将相同的文本搜索到我的数据库中的字段以获取实时搜索框。
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
在复制演员阵容时编辑错误。
答案 0 :(得分:1)
以下是我在主应用中解决此问题的方法。
我有一个主要实体,我希望用户能够搜索。称之为customer
。此实体在1:n contact
(用于电话,电子邮件等)表中包含关联的详细记录。
我定义了一个用于计算quicksearch密钥的视图customer_quicksearch
- 一个text
字段,其中包含客户contact
记录的串联以及customer
的一些记录直接领域。
我已向customer
和contact
customer_summary
表添加了触发器。当customer
中插入行时,customer_summary
触发器会将记录添加到customer
,并在删除customer
记录时删除该行。他们通过customer_summary
来自`customer_quicksearch的更新的quicksearch键更新SELECT
。我可以使用SQL函数代替视图,但发现视图更有用,更快。通过视图,可以更快地计算所有客户的快速搜索键,例如,批量插入或更新后。
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
记录。< / p>
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
索引以提高性能,但由于我主要进行没有左侧或右侧锚点的搜索 - LIKE '%search%'
- 这没有任何好处。
答案 1 :(得分:0)
No-op(转换为JOIN语法)(不是anwer!):
SELECT DISTINCT u.id, u.username
FROM
users AS u
JOIN user_invoice AS ui ON u.username like '%searchterm%'
OR ( ui.user_id = u.id AND ui.invoice = CAST('searchterm' AS INTEGER))
JOIN user_roles AS ur ON u.id = ur.user_id
JOIN roles AS r ON ur.role_id = r.id
WHERE r.name = 'teacher'
;
CAST('searchterm' AS INTEGER))
对我毫无意义。双引号?参数β