7

Tôi đã làm việc tối ưu hóa các cuộc gọi DB của dự án của tôi và tôi nhận thấy một sự khác biệt "đáng kể" trong hoạt động giữa hai cuộc gọi giống hệt dưới đây:Truy vấn ActiveRecord chậm hơn nhiều so với SQL thẳng?

connection = ActiveRecord::Base.connection() 
pgresult = connection.execute(
    "SELECT SUM(my_column) 
    FROM table 
    WHERE id = #{id} 
    AND created_at BETWEEN '#{lower}' and '#{upper}'") 

và phiên bản thứ hai:

sum = Table. 
     where(:id => id, :created_at => lower..upper). 
     sum(:my_column) 

Các phương pháp sử dụng phiên bản đầu tiên trên trung bình mất 300ms để thực thi (hoạt động được gọi là một vài nghìn lần tổng số trong đó), và phương pháp sử dụng phiên bản thứ hai mất khoảng 550ms. Tốc độ giảm gần như 100%.

Tôi đã kiểm tra lại SQL được tạo bởi phiên bản thứ hai, nó giống hệt với phiên bản đầu tiên có ngoại lệ đối với cột bảng chuẩn bị trước với tên bảng.

  • Tại sao chậm lại? Việc chuyển đổi giữa ActiveRecord và SQL có thực sự khiến cho hoạt động mất gần gấp 2 lần không?
  • Tôi có cần phải viết để viết SQL thẳng (có lẽ ngay cả một sproc) nếu tôi cần phải thực hiện các hoạt động tương tự một tấn thời gian và tôi không muốn để đạt trên không?

Cảm ơn!

+1

chỉ cần sử dụng .explain và nhìn vào truy vấn mà được tạo ra, tôi chắc chắn có vẻ khác nhau và thats lý do tại sao phải mất quá nhiều thời gian hơn – antpaw

+0

tôi kiểm tra lại kế hoạch truy vấn, họ đều giống hệt nhau, chi phí và tất cả các. Đã thay thế .select từ .sum trong phiên bản thứ hai, khi bạn nhận được một Fixnum trở lại từ đó và tôi không thể tìm thấy một cách để làm một. Giải thích về truy vấn đã được sử dụng để tạo ra nó. –

Trả lời

2

Một vài điều sẽ nhảy ra ngoài.

Thứ nhất, nếu mã này được gọi là 2000 lần và mất thêm 250ms để chạy, đó là 0.125ms cho mỗi cuộc gọi để chuyển đổi Arel thành SQL, điều này không thực tế. Thứ hai, tôi không chắc chắn về bên trong của Range trong Ruby, nhưng lower..upper có thể làm các phép tính như kích thước của phạm vi và những thứ khác, đó sẽ là một hit hiệu suất lớn.

Bạn có thấy cùng một lần truy cập hiệu suất như sau không?

sum = Table. 
     where(:id => id). 
     where(:created_at => "BETWEEN ? and ?", lower, upper). 
     sum(:my_column) 
+1

Theo như tôi hiểu, .. chỉ đơn giản là cú pháp đường mà ActiveRecord biến thành câu lệnh GIỮA nếu nó xác định rằng các toán hạng là các đối tượng Thời gian. Tôi đã thử phiên bản đó và tiếp tục nhận được các con số chính xác giống như phiên bản chậm. Về cơ bản, âm thanh như chuyển đổi đó đang chiếm thời gian. Tôi sẽ cấu hình nó để có được chi tiết hơn. –

+0

Vâng, nó vẫn phải tạo ra một đối tượng Range mà nó truyền vào, nhưng tôi đoán nó không làm bất kỳ công việc khó khăn nào vì một trình lặp không được tạo ra. AR có thể tạo đối tượng cho từng mục trước khi tổng hợp chúng không? Điều đó có thể làm chậm nó xuống. Dường như không chắc chắn. – iHiD

+0

Dựa trên lược tả, phiên bản đầu tiên nhảy thẳng vào thực hiện truy vấn. Tuy nhiên, phiên bản thứ hai dành khoảng 35% thời gian thực hiện tổng thể trên 30 cấp độ sâu của nhiều loại ma thuật AR khác nhau. Phiên bản chậm hơn phiên bản có thể được xem tại đây: http://pastebin.com/bipTy3c5 Phiên bản SQL thẳng là ở đây: http://pastebin.com/LysaGUTy –