Tối ưu hóa truy vấn từ database in rails

Khi làm việc với những project nhỏ, người lập trình thường ít để ý đến việc tối ưu hóa tốc độ truy vấn khi lấy dữ liệu từ database do lượng data nhỏ, số lượng table trong database còn ít, nên tốc độ nhanh hay chậm người lập trình khó nhận biết được. Tuy nhiên, khi làm việc với 1 project lớn hơn, các quan hệ giữa các bảng phức tạp hơn, số lượng bản ghi rất lớn, thì việc tối ưu hóa tốc độ lấy dữ liêu trở nên cần thiết, giảm tải cho database và giảm thời gian khi load trang web.

Sau 1 thời gian tìm hiểu, mình xin giới thiệu 1 số phương pháp mình biết để cải thiện tốc độ truy vấn từ database

  1. Sử dụng eager loading để tránh N+1 query

    N + 1 query là khái niệm được dùng để chỉ việc bạn load hàng loạt các object từ database lên sau đó thực hiện foreach trên các object và thực hiện các câu truy vấn trên các object đó.

    Bạn có thể tìm hiểu thêm về eager loading tại đây

    Việc sử dụng eager loading sẽ giúp bạn giảm được số lượng query từ N+1 thành 2 (preload hoặc includes) hoặc 1 (với eager_load). Như vậy với trường hợp có 1000 bản ghi bạn đã giảm số lượng truy vấn tới 500 lần, 1 con số rất lớn.

  2. Giảm lượng data lấy ra từ database

    Ta có thể tăng tốc lấy dữ liệu từ database bằng cách giảm số lượng fields lấy ra từ database.

      class Category < ActiveRecord::Base
        has_many :words, dependent: :destroy
      end

      class Word < ActiveRecord::Base
        belongs_to :category
      end
 Ở đây ta có 2 model như trên.ta có thể giảm lượng data lấy ra bằng cách sử dụng select hoặc pluck

 `words = Word.select(:content)`

 hoặc `words = Word.pluck(:content)`

Ở đây, 2 câu lệnh này đều trả về 1 mảng, tuy nhiên select trả về 1 mảng object, còn pluck trả về 1 mảng với phần tử là nội dung của content mỗi word.

Trong trường hợp này, ta đã giảm được số lượng data lấy ra từ mỗi bản ghi trong database, tuy nhiên khi sử dụng kết hợp vs eager loading thì association table( bảng quan hệ ) vẫn load toàn bộ các field của nó. Để giảm dữ liệu này t sử dụng joins và select. Để sử dụng được phương pháp này, ta cần có quan hệ 1-1 hoặc nhiều-1.

1 ví dụ đơn giản là:

`Word.joins(:category).select("words.content, categories.name AS category_name")`

Như vậy ta đã giảm được số lượng query và giới hạn dữ liệu lấy ra ở cả 2 bảng.

3. Các truy vấn có điều kiện cần được đưa vào trong scope

    Các scope được hỗ trợ bởi rails, giúp định nghĩa các điều kiện truy vấn, chúng ta có thể kết nối nhiều scope với nhau mà không tạo ra nhiều câu truy vấn. Các bạn quan tâm có thể tìm hiểu thêm về scope tại [đây](http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html)

Như vậy, mình đã giới thiệu cho các bạn 3 cách để tối ưu hóa truy vấn từ database, tất nhiên sẽ còn nhiều sai sót. Mong nhận được đóng góp từ các bạn


All Rights Reserved