Khi nào cần đánh index trong cơ sở dữ liệu
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 ...
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ụ:
User.find_by username: "shiroyasha" User.find_by email: "support@semaphoreci.com"
Chúng ta sẽ thêm index vào cột username, email của bảng usersadd_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ặc has_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ác branches thuộc project
class Project < ActiveRecord::Base has_many :branches end class Branch < ActiveRecord::Base belongs_to :project end
Để tìm kiếm nhanh chúng ta cần thêm index như sau:add_index :branches, :project_id
Trong trướng hợp có quan hệ sử dụng polymorphic, ví dụ owner của project có thể là user hoặc organizationclass 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
Thì chúng ta phải thêm index kép như sau: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ụ:
Build.order(:updated_at).take 10
Có thể được cải thiện bằng cách thêm index dành riêng: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