Cải thiện hiệu năng truy vấn database

Trải qua một vài dự án sử dụng rails, tôi nhận ra một vài điều không tốt trong rails project. Ví dụ như việc sử dụng Active record, nó thật sự không phải là cách hay trong nhiều trường hợp. Tôi thường sử dụng thời gia rảnh để tìm cách cả thiện tốc độ cho các câu truy vấn. Và tôi nhận ra một vài luật khi làm việc với database.

Rule 1: Hãy để database làm công việc của nó

Database là một feature cực kì mạnh mẽ, có tốc độ cao. Vì vậy bạn có thể giảm được đáng kể thời gian load page nếu như có thể tận dụng được các tính năng của nó. Nó có thể sort hay filter hay vô số các chức năng khác. Đối với những gì mà database có thể làm, tốt nhất hãy cho database làm. Nó sẽ thưc hiện nhanh hơn rất nhiều so với một điều tương tự được thực hiện bằng rails hay bất cứ ngôn ngữ lập trình nào. Tốt nhất bạn nên học một chút về cách mà database làm việc nhưng không nhất thiết phải hiểu sâu về nó. Tôi thường sử dụng postgresql cho các dự án của mình. Nhưng việc bạn sử dụng cái gì không quan trọng bằng việc bạn có thể hiểu nó và sử dụng một cách trơn tru các tính năng của nó. Nếu bạn có nhu cầu cần tìm hiểu về postgresql, hãy đọc tiếp bài viết này, t có rất nhiều suggest cho loại csdl này trong bài viết.

Rule 2: Viết ra các scope hiệu quả và dễ kết nối

Trước tiên thế nào là hiệu quả và dễ kết nối? ở basic level thì có thể hiểu đơn giản là scope chỉ nên return về relation. Như vậy các scope sẽ có khả năng tái sử dụng cao hơn rất nhiều. Lí do ruby mất nhiều thời gian hơn để thực hiện các tác vụ sort hay truy vấn đó là vì:

  • Việc lấy ra một đống dữ liệu không cần thiết xong lại mất công vận chuyển ra server rồi lại cắt bỏ nó đi thực sự rất thừa thãi.
  • Việc sử dụng active record để parse ra các câu truy vẫn và khởi tạo Active record model object cho mỗi record được lấy ra rất tốn thời gian.
  • Việc bạn đánh index trong db của bạn chính là một cách để tăng tốc độ truy vẫn, sử dụng filter bằng rails sẽ không sử dụng được chức năng này

Rule 3: giảm số lần call tới db

Cách này có thể thực hiện bằng nhiều cách, đó là lưu data vào nhiều redis, memcache ..... Nhưng trong đại đa số các trường hợp khi nhắc đến biện pháp này là sử dụng các methods như: .includes or .joins. Thỉnh thoảng là .group, .having và trong nhiều trường hợp hiếm hoi là viết thẳng lệnh SQL 😦

Rule 4: đánh index

Database có thể thực hiện fast look up cho những trường được đánh index Trên thực tế đây dũng không hoàn toàn là giải pháp hay vì đánh index quá nhiều cũng cũng là một nguyên nhân khiến không phải là một biện pháp tốt. Nhưng có dùng còn hơn không và nên sử dụng nó cho những gì thực sự cần thiết.

Rule 5: sử dụng query object cho những truy vấn phức tạp

Các Queries nên thực hiện trong query objects. Query object methods nên trả về một object, hash hay một array, không phải là một ActiveRecord association. Query object pattern giúp cho model của bạn liên kết chặt chẽ với một hành vi của một class (class’ behavior), trong khi vẫn đảm bảo controller được clean. Vì chúng không có gì hơn plain ola Ruby class, query object không cần phải kế thừa từ ActiveRecord::Base, và không phải chịu trách nhiệm gì khác hơn là các truy vấn thực hiện. Sử dụng class object cũng là một cách để đóng gói các câu truy vẫn phức tạp vào một mệnh đề riêng. Ví dụ:

class VolunteersNotMembersQuery
  def initialize(year:)
    @year = year
  end

  def relation
    volunteer_ids  = GroupMembership.select(:person_id).school_year(@year)
    pta_member_ids = PtaMembership.select(:person_id).school_year(@year)

    Person
      .active
      .adults
      .where(id: volunteer_ids)
      .where.not(id: pta_member_ids)
      .order(:last_name)
  end
end

Chú ý rằng kết quả của query object hoàn thoàn có thể phát triển tiếp vì nó return về ActiveRecord::Relation như .order , .limit ......

Rule 6: tránh sử dụng những câu truy vấn lồng bên trong scope và query object

Tôi không nhớ đã nghe thấy điều này ở đâu nhưng nó luôn là một điều nhắc nhở tôi:

Restrict access to ActiveRecord generic query-building methods (e.g. .where, .group, .joins, .not, etc) to scopes and Query objects.

Nghĩa là chỉ nên sử dụng các ActiveRecord generic query-building methods trong phạm vi scope và query object. Điều này để đảm bảo tính đóng gói của data bên trong scope hay query object. Mặt khác, sử dụng ad-hoc query trong controller sẽ rất khó để test độc lập và không thể tái sử dụng

tham khảo

http://blog.carbonfive.com/2016/11/16/rails-database-best-practices/

All Rights Reserved