Khi nào cần đánh index trong cơ sở dữ liệu
Bài đăng này đã không được cập nhật trong 3 năm
Các dự án Rails ban đầu thường sẽ hoạt động nhanh và ổn định. Nhưng sau khoảng vài tháng, khi số lượng người dùng sản phẩm bắt đầu tăng lên, các web request sẽ trở nên chậm hơn, việc sử dụng CPU của cơ sở dữ liệu tăng lên quá cao. Điều này dẫn đến việc, mặc dù chúng ta không thay đổi gì nhưng sản phẩm sẽ càng ngày càng trở nên chậm hơn. Vậy câu hỏi đặt ra là có cách nào để giải quyết vấn đề này, hay đơn giản bởi vì Rails không có khả năng mở rộng?
Điều gì làm cho ứng dụng Rails của bạn chậm?
Có thể có nhiều lí do khác nhau đằng sau sự chậm trễ của ứng dụng, tuy nhiên các truy vấn cơ sở dữ liệu thường đóng vai trò lớn nhất trong hiệu suất của một ứng dụng Rails. Load quá nhiều dữ liệu vào bộ nhớ, N+1 truy vấn, thiếu cache, thiếu index cho cơ sở dữ liệu là những nguyên nhân lớn nhất gây ra request chậm. Việc thiếu các index cho khóa ngoài, các cột hay được tìm kiếm, hoặc các giá trị cần được sắp xếp có thể tạo ra sự khác biệt rất lớn. Việc đánh index sẽ không đáng chú ý với những bảng chỉ có vài nghìn bản ghi, tuy nhiên khi dữ liệu của bảng đó nở ra vài triệu bản ghi, các tra cứu trong bảng sẽ trở nên rất chậm chạp.
Vai trò của index trong cơ sở dữ liệu
Khi bạn tạo một cột cơ sở dữ liệu, điều quan trọng là phải cân nhắc bạn có cần tìm và lấy các bản ghi dựa trên cột đó.
Ví dụ, trong dự án của chúng ta có sử dụng một model tên là Project
, có một attribute là name
, mỗi khi có một request từ client muốn show thông tin của một project thì trong controller sẽ xử lý:
project = Project.find_by name: params[:name]
Nếu không có index cho cột name
của bảng projects
thì khi đoạn code trên được chạy, cơ sở dữ liệu sẽ cần check các bản ghi của bảng projects
, từng cái một, cho đến khi tìm thấy hoặc duyệt qua hết tất cả các bản ghi.
Tuy nhiên, nếu chúng ta thêm index cho cột name
của bảng projects
, tra cứu sẽ nhanh hơn nhiều.
class IndexProjectsOnName < ActiveRecord::Migration
def change
add_index :projects, :name
end
end
Một cách rất hay để hiểu rõ hơn cơ chế hoạt động của index đó là chúng ta hãy tưởng tượng nó như mục lục trong mỗi cuốn sách. Bạn muốn tìm một phần nào đó, thay vì lật từng trang thì chúng ta sẽ tìm kiếm trong mục lục và đi thẳng đến trang có phần đó.
Những gì cần được đánh index
Một nguyên tắc chung là tạo index cho tất cả mọi thứ được tham chiếu trong các phần WHERE
, HAVING
và ORDER BY
của các truy vấn SQL.
- Index cho việc tìm kiếm giá trị duy nhất
Bất kỳ tìm kiếm dựa trên một giá trị cột duy nhất thì nên có index. Ví dụ:
Chúng ta sẽ thêm index vào cộtUser.find_by username: "shiroyasha" User.find_by email: "support@semaphoreci.com"
username
,email
của bảngusers
add_index :users :username add_index :users, :email
- Index cho khóa ngoài
Nếu bạn có các mối quan hệ của
belong_to
hoặchas_many
, bạn sẽ cần lập chỉ mục các khoá ngoại để tối ưu hóa việc tìm kiếm. Ví dụ chúng ta có cácbranches
thuộcproject
Để tìm kiếm nhanh chúng ta cần thêm index như sau:class Project < ActiveRecord::Base has_many :branches end class Branch < ActiveRecord::Base belongs_to :project end
Trong trướng hợp có quan hệ sử dụngadd_index :branches, :project_id
polymorphic
, ví dụowner
củaproject
có thể làuser
hoặcorganization
Thì chúng ta phải thêm index kép như sau:class Organization < ActiveRecord::Base has_many :projects, :as => :owner end class User < ActiveRecord::Base has_many :projects, :as => :owner end class Project < ActiveRecord::Base belongs_to :owner, :polymorphic => true end
add_index :projects, [:owner_id, :owner_type] # add_index :projects, :owner_id # add_index :projects, :owner_type # Cách này sẽ không cải thiện tốc độ tìm kiếm
- Index cho giá trị được sắp xếp
Bất kỳ việc săp xếp nào xảy ra thường xuyên cũng có thể được cải tiến bằng cách sử dụng index dành riêng.
Ví dụ:
Có thể được cải thiện bằng cách thêm index dành riêng:Build.order(:updated_at).take 10
add_index :updated_at
Có nên luôn luôn sử dụng index
Trong khi sử dụng các index cho các lĩnh vực quan trọng có thể cải thiện đáng kể hiệu suất ứng dụng của bạn, nhưng đôi lúc hiệu quả có thể là không đáng kể, hoặc nó thậm chí có thể làm cho ứng dụng của bạn chậm hơn. Ví dụ, các bảng có các phần tử thường xuyên bị xóa có thể tác động tiêu cực đến hiệu suất của cơ sở dữ liệu. Các bảng lớn với hàng triệu hồ sơ cũng đòi hỏi nhiều bộ nhớ hơn cho các index. Vì vậy, hãy luôn luôn hiểu về những thay đổi trong cơ sở dữ liệu của bạn, nếu không chắc chắn, hãy quyết định dựa trên số liệu đo thực tế.
Referrence: https://semaphoreci.com/blog/2017/05/09/faster-rails-is-your-database-properly-indexed.html
All rights reserved