20/09/2019, 18:55

Những cách làm app Rails chạy nhanh hơn

Người viết: Quỳnh “Rails chậm lắm” – đây có vẻ là câu nói có thể bạn hay thấy trên các diễn đàn khi đem các ngôn ngữ ra so sánh để hạ thấp nhau. Câu nói này thực ra cũng không sai. Ruby dường như chậm hơn các đối thủ cạnh tranh trực tiếp như Node.js , Python. Tuy ...

cách làm app Rails chạy nhanh hơn

Người viết: Quỳnh

“Rails chậm lắm” – đây có vẻ là câu nói có thể bạn hay thấy trên các diễn đàn khi đem các ngôn ngữ ra so sánh để hạ thấp nhau. Câu nói này thực ra cũng không sai. Ruby dường như chậm hơn các đối thủ cạnh tranh trực tiếp như Node.js, Python. Tuy nhiên, nhiều công ty startups nhỏ vẫn sử dụng nó để build nên các platform với hàng triệu user.

Vậy có thể giải thích sự mâu thuẫn này như thế nào?

  Hướng dẫn sử dụng Rails Engines thành công
  Kinh nghiệm phỏng vấn Basecamp - Tại sao 80% các ứng viên kỹ sư phần mềm bị người sáng lập Rails từ chối?

Điều gì làm cho app của bạn chậm?

Có rất nhiều lý do đằng sau nó, việc query và database dường như là 1 lý do lớn khiến performance của app thấp. Load quá nhiều data vào bộ nhớ, N+1 queries, nhiều values chưa được cache, quên đánh index là những nguyên nhân chủ chốt dẫn đến việc query chậm.

Thậm chí nếu app bạn đang chạy nhanh, nó vẫn có thể chậm đi chỉ trong vài tháng, các API đang gọi ngon lành đột nhiên lăn ra chết, HTTP 502 response xuất hiện. Sau tất cả thì việc làm việc với các bảng dữ liệu vài trăm records rất khác so với bảng cả triệu records.

Xem thêm API là gì

Việc kiểm tra sự tồn tại của đối tượng

Hay còn gọi là “existence check”, việc này khá phổ biến khi làm việc với database. Có rất nhiền cách để thực hiện existence check, chúng ta có các method như present?, empty?, any?, exists?. Nhưng mỗi method này lại có sự khác nhau rất lớn về performance.

Method luôn được recommend là .exists?.

Ví dụ: ta muốn tìm ra 1 bản build passed trong vòng 7 ngày đổ lại. Hãy xem các trường hợp dưới đây:

Cách gọi đầu tiên sử dụng .present?rất không hiệu quả. Nó load toàn bộ record của database vào bộ nhớ, tạo nên các Active Record objects, sau đó bắt đầu tìm theo điều kiện. Nếu có 1 table lớn, việc tìm kiếm sẽ trở nên rất mệt mỏi, load 1 lúc cả triệu records và gây downtime cho app.

Cách tiếp cận thứ 2 và 3, any?, empty? đã được optimized trong Rails và chỉ load COUNT(*) vào bộ nhớ, queries kiểu COUNT(*) thường hiệu quả hơn, ta có thể dùng nó thậm chí trong những table to mà không cần phải lo gì.

Còn cách thứ 4, exists?, được optimized tốt hơn nữa, nó nên là lựa chọn số 1 khi kiểm tra sự tồn tại của record, SELECT 1 ... LIMIT 1, siêu nhanh, nhỉ?

OK, đây là kêt quả của từng queries:

Chỉ 1 tinh chỉnh nhỏ này cũng có thể làm code của bạn chạy nhanh hơn 400 lần trong vài trường hợp nào đó.

Thế có nên lúc nào cũng dùng exists? không?

Mình cũng băn khoăn, có phải liệu nó có nên được mặc định cho việc tối ưu hiệu suất? Tuy nhiên cũng có vài ngoại lệ.

Ví dụ, nếu mình check tồn tại của 1 association record mà ko dùng scope, thì any?, empty? cũng cung cấp dạng query tối ưu kiểu SELECT 1 FROM … LIMIT 1, nhưng any? không thọc vào database nữa nếu record đó đã được load vào bộ nhớ. Đỉnh chưa?

Kết luận cuối cùng là vẫn nên xài exists?!

Quy tắc đánh index

Khi tạo 1 column, cần xem thử column đó có dùng để tìm kiếm, lấy ra nhiều ko. Ví dụ ta có model Project, với thuộc tính “name”. Hiển nhiên việc tìm kiếm project bằng name diễn ra khá thường xuyên:

Nếu không có index, database engine sẽ phải check từng record một trong table projects cho tới khi nào tìm thấy thì thôi.

Nếu ta đánh index vào thì sao? Việc tìm kiếm sẽ trở nên rất nhanh.

Index giống như mục lục 1 cuốn sách, ta có thể đọc cả cuốn sách để tìm 1 từ, hoặc chỉ cần mở phụ lục, tìm đến phần chứa các từ quan trọng đã sắp xếp theo alphabet, lật đến trang đó và tìm trong đó thôi.

Đơn giản hơn nhiều phải không?

Cái gì cần đánh index?

Quy tắc ngón tay cái là đánh index cho mọi thứ liên quan đến WHERE, HAVING và ORDER BY trong SQL queries.

Index cho tìm kiếm duy nhất

Việc tìm kiếm dựa trên column chứa giá trị duy nhất nên cần được đánh index. Ví dụ:

query trên sẽ rất xịn xò nếu mình đánh index cho username và email:

Index cho khóa ngoại (foreign keys)

Nếu có các relationship như belongs_to, has_many thì việc đánh index cho các khóa ngoại sẽ giúp tối ưu quá trình tìm kiếm.

Ví dụ:

Muốn tìm nhanh thì cần đánh index như bên dưới:

Với polymorphic associations, owner của project đồng thời có thể là User hoặc là Organization:

Ta cần 1 cái double index:

Index cho việc sắp xếp

Các đối tượng được sắp xếp thường xuyên đều nên được đánh index.

Ví dụ:

Nên cần:

Có nên lúc nào cũng đánh index không?

Việc dùng index cho các field quan trọng có thể giúp cải thiện performance, nhưng bên cạnh đó cũng có thể làm app chậm hơn.

Ví dụ, table có nhiều phần tử thường xuyên bị xóa có thể gây ảnh hưởng tiêu cực đến performance. Table lớn với cả triệu record sẽ cần nhiều bộ chứa để lưu index. Tùy theo tình huống để đưa ra quyết định hợp lý.

Ref: https://link.sun-asterisk.vn/cL9owP, https://link.sun-asterisk.vn/0pVkWy

Có thể bạn quan tâm:

  • Một số method & phong cách code hay trong Rails
  • Ruby on Rails là gì?
  • Mẫu bảng công việc lập trình Ruby on Rails mức lương hấp dẫn

Xem thêm việc làm Software Developers tại TopDev

TopDev via viblo.asia

  5 lỗi bảo mật cơ bản trong Rails app hay gặp trong thực tế
  Hệ gợi ý bằng thuật toán Sørensen–Dice trong Rails với gem Predictor
0