Rails:提高简单搜索方法的性能

这些天我一直在构建应用程序。 function完全没什么特别的,我必须连接到客户端的SOAP Web服务,获取一些数据,将其保存到我的pg数据库中,并根据这些数据构建搜索function。

搜索必须在两个表上执行,两者组合都是80K行。 它需要在这两个表中的几个字段中查找输入文本中的每个单词,这两个表具有一对多的经典关联。

以前让我的手弄脏了我看着我必须完成function的选择(ransack,searchkick,scoped_search等),但我最终尝试只是vanilla Active Record而且我很惊讶地发现我可以实现function方式比我想象的更容易,并且具有可接受的响应时间,对于本地最昂贵的查询,大约400ms的活动记录时间。

所以问题是,这个应用程序在Heroku中的性能比在本地更差(我正在开发使用流浪盒btw)。 平均而言,查询所需的时间比本地查询长2-3倍,因此用户体验从可接受到穷人。 我想知道是否有人可以帮助改善我的查询。 我也担心获取数据的后台工作如何在本地以及存储器的某些问题上表现得很差,但这是一个不同的故事。

相关的片段是这些:

part_master.rb ,其中实现了搜索方法:

 class PartMaster  { where("stock > 0") } scope :planta, -> (planta) { where planta_cod: planta} def self.search(params) recordset = PartMaster.joins(:part_variants).all recordset = recordset.con_stock if params[:stock].present? recordset = recordset.planta(params[:planta]) if params[:planta].present? recordset = search_keywords(params[:search], recordset) recordset end private def self.search_keywords(query, recordset) keywords = query.to_s.strip.split if query keywords.each do |keyword| recordset = recordset.where('part_masters.sap_cod ILIKE :q OR unaccent(descripcion_maestro) ILIKE unaccent(:q) OR fabricante ILIKE :q OR ref_fabricante ILIKE :q OR fabricante_prov ILIKE :q OR ref_prov ILIKE :q', q: "%#{keyword}%") end recordset.distinct.order(:sap_cod) end end end 

这是从控制器调用方法:

  def index parts = params[:search].present? ? PartMaster.search(params) : PartMaster.none @parts = parts.page(params[:page]).per(50) end 

我在每个可搜索字段中都有一个索引。

编辑:最后我在答案中尝试了混合提案。 我在每个表中创建了一个字段,它是搜索相关字段的串联,有2个OR语句而不是5个,我还在两个新字段中都放置了trigram GIN索引。 我没有看到任何改进,与ActiveRecord相对应的时间非常相似,可能稍微好一点。

问题是,使用EXPLAIN的查询输出无法显示有关正在使用的索引的任何信息。

 Hash Join (cost=2243.29..6067.41 rows=2697 width=132) Hash Cond: ((part_variants.sap_cod)::text = (part_masters.sap_cod)::text) Join Filter: ((part_masters.combinada_maestro ~~* '%rodamiento%'::text) OR (part_variants.combinada_info ~~* '%rodamiento%'::text)) -> Seq Scan on part_variants (cost=0.00..1264.96 rows=54896 width=18) -> Hash (cost=1128.13..1128.13 rows=34813 width=132) -> Seq Scan on part_masters (cost=0.00..1128.13 rows=34813 width=132) (6 rows) 

提高AR查询速度的建议使用模型中的直接Postgresql查询

在关键字循环中的示例

 query = "SELECT * FROM part_masters WHERE......" PartMaster.connection.execute(query, :skip_logging) 

我同意spikermann。 循环中的多个OR也没有帮助。

如果您只想使用vanilla解决方案而不是添加SOLR或任何其他引擎,则可以使用一个单独的字段来保存要搜索的字符串的副本。 (例如姓名,描述,……)。 仅搜索此字段。 当名称,描述或其他值发生更改时,您将需要一些方法来更新字段。