postgresql - 使用 Postgres 在多个字段中搜索一个术语

标签 postgresql

我正在尝试在我的数据库中的字段中搜索相同的文本以查找实时搜索框。

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 字段。

我已将触发器添加到 customercontact 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 触发器来处理客户的insertupdatedelete,维护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/

相关文章:

sql - Postgres 解决由破折号(-)引起的语法错误

postgresql - find_or_create_by - id = nil 当记录存在时

sql - 在数据库字段中搜索元数组

java - 无法在 native sql 查询中获取默认架构

sql - 如何从 PostgreSQL 中的文本中删除分隔部分?

node.js - 为什么要 Sequelize db :create command is not working

postgresql - pg_restoring 非常大的单表使用 -j 选项需要几个小时

sql - 全文搜索返回太多不相关的结果并导致性能不佳

postgresql - 优化拥有近 1.5 亿条记录的 Postgres DB

delphi - PostgreSQL 上的 UniDac : no value on serial (autoincrement) field after insert