Postgresql 如何在具有多个或多个属性的postgres中为文本搜索查询构造索引

Postgresql 如何在具有多个或多个属性的postgres中为文本搜索查询构造索引,postgresql,indexing,text-search,Postgresql,Indexing,Text Search,外部连接器在我的postgres数据库上创建了一个非常糟糕的请求。但这是一项业务需求,不幸的是,我无法更改请求 请求看起来像这样 SELECT avantage.id FROM avantage WHERE (CAST(avantage.web_prepaye_cda_codepin AS TEXT) LIKE '%' || 'searchword' || '%') = true OR (CAST(avantage.type AS TEXT) LIKE '%' || 'searchword'

外部连接器在我的postgres数据库上创建了一个非常糟糕的请求。但这是一项业务需求,不幸的是,我无法更改请求

请求看起来像这样

SELECT avantage.id
FROM avantage 
WHERE (CAST(avantage.web_prepaye_cda_codepin AS TEXT) LIKE '%' || 'searchword' || '%') = true
OR (CAST(avantage.type AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.statut AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.soustype AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.source AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.prepaye_cda_codepin AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.typedeclenchement__c AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.receivedby__c AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.givenby__c AS TEXT) LIKE '%' || 'searchword' || '%')  = true 
OR (CAST(avantage.numero_ticket AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.numero_carte AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.nom_avantage AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.last_modified_by AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.id_carte AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.icu AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.description AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.account_id AS TEXT) LIKE '%' || 'searchword' || '%') = true 
OR (CAST(avantage.created_by AS TEXT) LIKE '%' || 'searchword' || '%') = true 
ORDER BY  avantage.id LIMIT 30 OFFSET 0;
我尝试在每个字段上添加Gin索引,如下所示:

CREATE INDEX trgm_avantage_web_prepaye_cda_codepin_idx
  ON avantage
  USING gin
  (CAST(web_prepaye_cda_codepin AS TEXT)  COLLATE pg_catalog."default" gin_trgm_ops);
...
...
就个人而言,它运行良好

它可以在5到7种条件下正常工作(取决于选择的条件)。 但随着条件的增加,Postgres会停止使用索引,并创建一个经典的超长过滤查询:

 Limit  (cost=0.09..217.47 rows=1 width=8) (actual time=15952.773..15952.773 rows=0 loops=1)
   ->  Index Scan using avantage_pkey on avantage  (cost=0.09..546295.48 rows=2513 width=8) (actual time=15952.771..15952.771 rows=0 loops=1)
         Filter: (((web_prepaye_cda_codepin)::text ~~ '%searchword%'::text) OR ((type)::text ~~ '%searchword%'::text) OR ((statut)::text ~~ '%searchword%'::text) OR ((soustype)::text ~~ '%searchword%'::text) OR ((source)::text ~~ '%searchword%'::text) OR ((prepaye_cda_codepin)::text ~~ '%searchword%'::text) OR ((typedeclenchement__c)::text ~~ '%searchword%'::text) OR ((receivedby__c)::text ~~ '%searchword%'::text) OR ((givenby__c)::text ~~ '%searchword%'::text) OR ((numero_ticket)::text ~~ '%searchword%'::text) OR ((numero_carte)::text ~~ '%searchword%'::text) OR ((nom_avantage)::text ~~ '%searchword%'::text) OR ((last_modified_by)::text ~~ '%searchword%'::text) OR ((id_carte)::text ~~ '%searchword%'::text) OR ((icu)::text ~~ '%searchword%'::text) OR ((description)::text ~~ '%searchword%'::text) OR ((account_id)::text ~~ '%searchword%'::text) OR ((created_by)::text ~~ '%searchword%'::text))
         Rows Removed by Filter: 8028920
 Planning time: 0.922 ms
 Execution time: 15952.814 ms
我不知道查询中可能的最大索引扫描有什么限制吗? 有没有其他方法可以在不接触查询的情况下优化查询

尝试使用

ORDER BY avantage.id + 0

因此,PostgreSQL无法使用它所做的索引扫描,因为它估计的结果数量是错误的。

我确信有一个限制,但您没有遇到它。如果需要,PostgreSQL可以创建具有1000个位图索引扫描的位图映射器。我不知道能比这个高多少,但一个表中只能有1600列,这将给事情设置一个实际的限制

它最终改变计划仅仅是因为它认为(似乎是错误的)另一个会更快。每增加一个OR,规划人员就会认为它将处理结果中更多的行,这使得使用主键索引(避免排序并允许提前停止)看起来越来越有吸引力

如果您不能以任何方式触摸查询,您可以触摸什么?能否将查询包装在
set enable_indexscan=off;重置启用索引扫描

你能去掉主键吗?如果它只用于维护唯一性,而不用于查询或外键,那么您可以在(id+0)上用唯一索引替换它

也许您可以全局地将enable_indexscan设置为off,或者仅针对这一个用户(
alter user_name set enable_indexscan=off
)?这不是很理想,但你在这里刮桶底。大多数索引扫描只会转换为位图扫描,它们的性能不会有太大变化。问题是,仅索引扫描也将被禁用,以及使用索引实现排序,位图扫描并不能有效地替代这两种扫描。但也许你并不真正依赖这些东西


还有一些方法可以使用连接池拦截和重写查询。也许你可以用类似的东西。我没有用过,所以不能推荐。我知道pgbouncer rr。

您不能更改请求,还是他们只是想要期望的结果?我认为问题出在演员阵容上。是否可以强制转换输入而不是(整个)数据集?与您的问题无关,但是:
where(x-like'…')=true
可以简化为
where x-like'…'
您可以比较此查询性能吗?“avantage.type 124?|;;; avantage.Stud ||;;avantage.类型124?|;; avantage.身材.身材| | avantage.SaSasage.Did从avantage中选择avantage.id.id从avantage的avantage中选择avantage.id.id,从avantage的avantage的avantage.id。从avantage的avantage.id。从avantage的avantage的avantage。从该文文文文从该文文文文文文文文文。id。id的文文。id。id。从该文文文文文文文文文文。从文从文文文文文文文文文文文文文文文文。。。文。从文。文。文。文。文。文。文。文。文。id的文。id的文。id的文U carte||avantage.nom|u avantage|avantage.last|u修改|avantage.id|u carte|avantage.icu|avantage.description|avantage.account|id|avantage.created|u由类似“%”搜索词“| avantage.id限制30偏移量0”;对不起,伙计们,请求是由连接器自动生成的。我只是不能在iTunes上做任何事情,我甚至不能包装查询。我的想法是,博士后在计划化方面也会犯错误,因为有了所有索引后,请求的计划化时间要比没有索引时长。你是指计划所需的时间,还是计划树本身在内存中的大小?我认为两者都不相关,只是估计的行数。我编辑了一些描述,还有一些更多(不太理想的)选择。我真的不知道。我只知道在超过5到7种情况下,博士后开始忽略指数。