【问题标题】:Complex filtering in rails app. Not sure complex sql is the answer?Rails 应用程序中的复杂过滤。不确定复杂的sql是答案吗?
【发布时间】:2013-03-23 19:25:45
【问题描述】:

我有一个应用程序,它允许用户根据一组非常大的标准过滤申请人。每个条件都由跨越数据库中多个表的布尔列表示。我认为最好使用纯 sql 并将大部分工作放在数据库中,而不是使用活动记录模型。为了做到这一点,我必须根据用户选择的条件构建一个相当复杂的 sql 查询,然后通过数据库上的 AR 运行它。有一个更好的方法吗?我想在同时拥有可维护和非易碎代码的同时最大限度地提高性能?任何帮助将不胜感激。

【问题讨论】:

    标签: mysql ruby-on-rails performance filtering


    【解决方案1】:

    正如@hazzit 所说,没有太多细节很难回答,但这是我的两分钱。通常需要使用原始 SQL 来执行聚合、计算等复杂操作。但是,当涉及到搜索/过滤功能时,我经常发现使用原始 SQL 有点矫枉过正,而且不太易于维护。

    这里的关键问题是:你能把你的问题分解成多个独立的过滤器吗? 如果答案是肯定的,那么您应该利用 ActiveRecord 和 Arel 的强大功能。我经常发现自己在我的模型中实现了这样的东西:

    scope :a_scope, ->{ where something: true }
    scope :another_scope, ->( option ){ where an_option: option }
    scope :using_arel, ->{ joins(:assoc).where Assoc.arel_table[:some_field].not_eq "foo" }
    # cue a bunch of scopes
    
    def self.search( options = {} )
      output   = relation
      relation = relation.a_scope if options[:an_option]
      relation = relation.another_scope( options[:another_option] ) unless options[:flag]
      # add logic as you need it
    end
    

    此解决方案的美妙之处在于您声明了一个干净的界面,您可以在其中直接从复选框和字段中倾倒所有参数,并返回一个关系。将查询分解为多个可重用的范围有助于保持事物的可读性和可维护性;使用search 类方法将所有内容联系在一起并允许完整的文档...总而言之,使用 Arel 有助于保护应用程序免受注入。

    附带说明,这并不妨碍您使用原始 SQL,只要查询可以在范围内隔离。

    如果此方法不适合您的需求,还有另一种选择:使用成熟的搜索/过滤解决方案,如 Sunspot。这将使用与您的数据库分开的另一个存储,该存储为您的数据的已定义部分编制索引,以便于轻松和高效地搜索。

    【讨论】:

    • 谢谢。我会考虑的。我不需要进行任何聚合,因此范围解决方案可能对我很有效。
    【解决方案2】:

    如果不了解更多细节,很难完全回答这个问题,但我还是会尝试。

    虽然数据库在很多方面都不擅长,但它们非常擅长过滤数据,尤其是在处理大量数据时。

    如果您在 Ruby on Rails(或任何其他编程语言)中进行过滤,系统将不得不从数据库中检索所有未过滤的数据,这将导致大量磁盘 I/O 和网络(或进程间)流量。然后它必须遍历内存中所有未过滤的结果,这可能对 RAM 和 CPU 造成很大负担。

    如果您在数据库中进行过滤,则很有可能大多数记录将永远不会真正从磁盘中检索,不会移交给 RoR,也不会被过滤。索引甚至存在的主要原因是为了避免昂贵的操作以加快速度。 (是的,它们还有助于维护数据完整性)

    但是,要完成这项工作,您可能需要稍微帮助数据库以有效地完成其工作。您必须创建与您的过滤条件匹配的索引,并且您可能必须研究某些类型的查询的性能问题(如何避免临时表等)。但是,这绝对是值得的。

    话虽如此,实际上有几种类型的查询是给定数据库不擅长的。这些很少,而且相距甚远,但它们确实存在。在这些情况下,在 RoR 中实现可能是更好的方法。即使不了解您的场景的更多信息,我也可以肯定您的查询不在其中。

    【讨论】:

    • 感谢您的帮助。我正在处理的情况是我的申请人可以填写由 30 到 40 个复选框组成的个人资料。用户需要能够根据位置和申请人输入的条件过滤申请人。所以从本质上讲,用户理论上可以搜索所有懂西班牙语、德语和英语的导师,他们辅导数学和科学,也做 SAT 考试准备,我目前这样做的方式是使用逻辑来构建复杂的sql语句。我想知道这是否是解决这个特定问题的最佳解决方案。
    • 您所描述的内容听起来像是一个非常正常的过滤场景,所以是的,我建议在 SQL 中进行。您可能可以通过使用 RoR 来减少复杂性,以避免昂贵的连接(例如,如果您知道某个子查询只会有一个结果,您可能只想将其作为单独的查询来执行,从而降低主查询)
    猜你喜欢
    • 2011-04-14
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    相关资源
    最近更新 更多