【问题标题】:LIKE search of joined and concatenated records is really slow (PostgreSQL)LIKE 搜索连接和连接的记录真的很慢(PostgreSQL)
【发布时间】:2017-08-08 17:02:55
【问题描述】:

我从 users 表中返回了一个唯一的 id 列表,相关表 (positions) 中的 where 特定列包含匹配的字符串。

每个用户记录的相关表可能有多个记录。

查询花费了非常长的时间(它不可扩展),所以我想知道我是否以某种基本方式构造了错误的查询?

用户表:

id | name
-----------
1  | frank
2  | kim
3  | jane

职位表:

id | user_id | title     | company | description
--------------------------------------------------
1  | 1       | manager   | apple   | 'Managed a team of...'
2  | 1       | assistant | apple   | 'Assisted the...'
3  | 2       | developer | huawei  | 'Build a feature that...'

例如:如果相关的positions 记录在titlecompanydescription 列中包含“apple”,我想返回用户的id

查询:

select
  distinct on (users.id) users.id,
  users.name,
  ...
from users
where (
    select
        string_agg(distinct users.description, ', ') ||
        string_agg(distinct users.title, ', ') ||
        string_agg(distinct users.company, ', ')
    from positions
    where positions.users_id::int = users.id
    group by positions.users_id::int) like '%apple%'

更新

我喜欢将其移入join 子句的想法。但我要做的是根据以下条件过滤用户。而且我不确定如何在join 中做到这两点。

1) 在标题、公司、描述中查找关键字

or

2) 通过全文搜索在另一个表中的文档的关联字符串版本中查找关键字。

select
    to_tsvector(string_agg(distinct documents.content, ', '))
from documents
where users.id = documents.user_id
group by documents.user_id) @@ to_tsquery('apple')

所以我最初认为它可能看起来像,

select
  distinct on (users.id) users.id,
  users.name,
  ...
from users
where (
    (select
        string_agg(distinct users.description, ', ') ||
        string_agg(distinct users.title, ', ') ||
        string_agg(distinct users.company, ', ')
    from positions
    where positions.users_id::int = users.id
    group by positions.users_id::int) like '%apple%')
    or
    (select
        to_tsvector(string_agg(distinct documents.content, ', '))
    from documents
    where users.id = documents.user_id
    group by documents.user_id) @@ to_tsquery('apple'))

但是它真的很慢 - 我可以确认缓慢是来自第一个条件,而不是全文搜索。

【问题讨论】:

    标签: postgresql group-by sql-like string-aggregation


    【解决方案1】:

    可能不是最好的解决方案,但一个快速的选择是:

    SELECT  DISTINCT ON ( u.id ) u.id,
            u.name
    FROM    users u
    JOIN    positions p ON (
                     p.user_id = u.id
                AND  ( description || title || company )
                LIKE '%apple%'
            );
    

    基本上摆脱了子查询,不必要的string_agg使用,位置表分组等。

    distinct on 涵盖了它的作用是进行条件连接和删除重复项。

    PS!我使用表别名 up 来缩短示例

    编辑:还应要求添加 WHERE 示例

    SELECT  DISTINCT ON ( u.id ) u.id,
            u.name
    FROM    users u
    JOIN    positions p ON ( p.user_id = u.id )
    WHERE   ( p.description || p.title || p.company ) LIKE '%apple%'
    OR      ...your other conditions...;
    

    EDIT2: 新细节揭示了对原始问题的新要求。因此,为更新的问题添加新示例:

    由于您使用 OR 条件查找 2 个不同的表(位置和上传),因此简单的 JOIN 将不起作用。 但是这两种查找都是验证类型的查找——只查找%apple% 存在,那么您不需要聚合和分组和转换数据。 无论如何,使用返回TRUEEXISTS 来查找第一个匹配项似乎是您所需要的。因此,删除所有不必要的部分并使用 LIMIT 1 在找到第一个匹配项时返回正值,如果没有找到则返回 NULL(后者将使 EXISTS 变为 FALSE)会给你同样的结果。

    所以你可以这样解决它:

    SELECT  DISTINCT ON ( u.id ) u.id,
            u.name
    FROM    users u
    WHERE   EXISTS (
                SELECT  1
                FROM    positions p
                WHERE   p.users_id = u.id::int
                AND     ( description || title || company ) LIKE '%apple%'
                LIMIT   1
            )
    OR      EXISTS (
                SELECT  1
                FROM    uploads up
                WHERE   up.user_id = u.id::int -- you had here reference to table 'document', but it doesn't exists in your example query, so I just added relation to 'upoads' table as you have in FROM, assuming 'content' column exists there
                AND     up.content LIKE '%apple%'
                LIMIT   1
            );
    

    注意!在您的示例查询中,引用了 documents 之类的表/别名,这不会反映 FROM 部分中的任何位置。因此,要么你在你的示例真实查询中使用错误的命名,要么你以其他方式拼写错误,你需要相应地验证和调整我的示例查询。

    【讨论】:

    • 是否可以在where 子句中包含它?我需要添加一个or,然后添加另一个条件
    • 参见 EDIT2。此外,您尝试过的查询示例中存在拼写错误或复制粘贴错误;)
    猜你喜欢
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 2015-11-02
    相关资源
    最近更新 更多