合并where条款的性能问题

时间:2019-05-31 08:40:48

标签: postgresql full-text-search

问题

我想知道:如何重写/更改搜索查询/策略以获得最终用户可接受的性能?

搜索

我正在为我们的用户实施搜索,为他们提供了基于以下条件在我们的系统上搜索候选人的能力:

  • 他们所属的专业团体
  • 位置+半径
  • 全文搜索。

查询

select v.id
    from (
        select
            c.id,
            c.ts_description,
            c.latitude,
            c.longitude,
            g.group
        from entities.candidates c
        join entities.candidates_connections cc on cc.candidates_id = c.id
        join system.groups g on cc.systems_id = g.id
    ) v

    -- Group selection
    where v.group = 'medical'

    -- Location + radius
    and earth_distance(ll_to_earth(v.latitude, v.longitude), ll_to_earth(50.87050439999999, -1.2191283)) < 48270

    -- Full text search
    and v.ts_description @@ to_tsquery('simple', 'nurse | doctor')
;

数据大小和基准

我正在处理170万条记录

我按影响顺序列出了三个条件,分别进行了基准测试:

  • Group子句:3s并减少到70万条记录
  • 位置子句:8s并减少到54k条记录
  • 全文子句:60s +并减少到1万条记录

当将它们组合在一起时,似乎要花费71s,这是3个查询的全部影响,我的期望是,当将所有3个子句放在一起时,它们将顺序工作,即对上一个子句的数据子集起作用,因此计时应该大大减少-但这没有发生。

我尝试过的事情

  • 所有联接条件和where子句被索引
  • 尤其是ts_description索引(GIN)为2GB
  • lat / lng使用ll_to_earth()进行索引,以减少内联影响
  • 我将每个where子句按顺序嵌套到另一个子查询中
  • 更改了所有子句和子查询的顺序
  • 增加shared_buffers的大小以增加潜在的高速缓存命中率

2 个答案:

答案 0 :(得分:0)

似乎不需要子查询,并且使用数字字段进行过滤也是一种好习惯,因此,例如,不要使用where v.group = 'medical'进行过滤,而是创建一个字典并使用{{1}进行过滤}

where v.group = 1

还要使用 select DISTINCT c.id, from entities.candidates c join entities.candidates_connections cc on cc.candidates_id = c.id join system.groups g on cc.systems_id = g.id where tablename.group = 1 and earth_distance(ll_to_earth(v.latitude, v.longitude), ll_to_earth(50.87050439999999, -1.2191283)) < 48270 and v.ts_description @@ to_tsquery(0, 1 | 2) 查看并检查您的执行计划。这些快速提示将帮助您清楚地进行改进。

答案 1 :(得分:0)

我没有考虑过一些最佳实践案例,后来我实施了这些案例以显着提高性能:

tsvector索引大小减小

我在tsvector中最多存储25,000个字符,这意味着当使用更复杂的全文本搜索查询时,要做的工作量非常大,我将其减少到10,000个,这产生了很大的不同。对于我的用例,这是一个可以接受的折衷方案。

创建实例化视图

我创建了一个包含联接的实例化视图,这减轻了工作量,此外,我还在此处建立了索引,并每隔2小时运行一次并发刷新。这给了我一个非常稳定的表来使用。

即使我的搜索产生了1万条记录,但最终我还是在前端进行分页,所以我最多只能在屏幕上显示100条结果,但这使我只能加入100条记录的原始表要发回去。

增加RAM并利用pg_prewarm

我增加了服务器RAM,为我提供了足够的空间来存储实例化视图,然后在实例化视图上运行pg_prewarm。将其保存在内存中对我来说是最大的性能提升,使2m查询降低到3s。