ユーザーが非常に大きな基準セットに基づいて応募者をフィルタリングできるようにするアプリケーションがあります。基準はそれぞれ、データベース内の複数のテーブルにまたがるブール列によって表されます。アクティブ レコード モデルを使用する代わりに、純粋な sql を使用して作業の大部分をデータベースに置くのが最善だと考えました。これを行うには、ユーザーが選択した基準に基づいてかなり複雑な SQL クエリを作成し、データベースで AR を介して実行する必要があります。これを行うより良い方法はありますか?メンテナンス可能で脆弱でないコードを同時に使用しながら、パフォーマンスを最大化したいですか? どんな助けでも大歓迎です。
2 に答える
詳細を知らずにこの質問に完全に答えるのは難しいですが、とにかく試してみます。
データベースは多くの点で苦手ですが、特に大量のデータをフィルタリングするのは得意です。
Ruby on Rails (または他のプログラミング言語) でフィルタリングを行う場合、システムはデータベースからフィルタリングされていないデータをすべて取得する必要があり、大量のディスク I/O とネットワーク (またはプロセス間) トラフィックが発生します。 . 次に、フィルター処理されていないすべての結果をメモリ内で処理する必要があり、これは RAM と CPU にかなりの負荷をかける可能性があります。
データベースでフィルタリングを行うと、ほとんどのレコードが実際にディスクから取得されず、RoR に渡されず、フィルタリングされない可能性がかなり高くなります。インデックスが存在する主な理由は、高速化のために高価な操作を回避するという唯一の目的のためです。(はい、データの整合性の維持にも役立ちます)
ただし、これを機能させるには、データベースが効率的にジョブを実行できるようにする必要がある場合があります。フィルター条件に一致するインデックスを作成する必要があり、特定の種類のクエリでパフォーマンスの問題を調べる必要がある場合があります (一時テーブルを回避する方法など)。しかし、それは間違いなく価値があります。
そうは言っても、実際には、特定のデータベースが苦手なタイプのクエリがいくつかあります。それらはほとんどありませんが、存在します。そのような場合、RoR での実装がより良い方法かもしれません。あなたのシナリオについて詳しく知らなくても、あなたのクエリがそれらの中にないことはかなり安全な賭けだと思います.
@hazzit が言ったように、あまり詳細がないと答えるのは難しいですが、これが私の 2 セントです。集計や計算などの複雑な操作を実行するには、通常、生の 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のような本格的な検索/フィルタリング ソリューションを使用します。これは、データベースとは別の別のストアを使用し、データの定義された部分にインデックスを付けて、簡単でパフォーマンスの高い検索を行います。