2013-06-09 16 views
9

Trong home_controller của Rails của tôi 4 ứng dụng, tôi thực hiện một truy vấn tùy chỉnh sql và lưu kết quả vào một thể hiện biếnCó thể cache truy vấn sql tùy chỉnh trong Rails không?

@studentscoring = ActiveRecord::Base.connection.execute sql_string_student 

tôi sau đó, sau khi cài đặt bộ nhớ đệm để đúng trong phát triển cấu hình config.action_controller.perform_caching = true và khởi động lại ứng dụng, thiết lập lên bộ nhớ đệm xung quanh biến có liên quan trong chế độ xem.

<% cache @studentscoring do%> 
    <% for lawyer in @studentscoring %> 
    <div class="span2"> 
     <div class="row"> 
     <%= tiny_gravatar_for lawyer['name'], lawyer['email'] %> 

     </div> 
     ...... #code ommitted 
    </div> 

    <% end %> 
    <% end %> 

Refreshing trình duyệt ba lần cho thấy rằng các truy vấn được chạy ba thời điểm khác nhau và thời gian cuối cùng của truy vấn thực sự mất .7ms dài hơn lần đầu tiên, vì vậy tôi giả sử bộ nhớ đệm không hoạt động hoặc tôi không làm đúng cách :). Bạn có thể cho tôi biết tôi đang làm gì sai không?

Không phải là chuyên gia theo bất kỳ tiêu chuẩn nào, tôi không hiểu cách bộ nhớ đệm có thể được kích hoạt từ chế độ xem với bộ nhớ cache <% ... do%> cú pháp, do thời gian lượt xem không có truy vấn điều khiển đã được chạy, do đó quá muộn để yêu cầu Rails sử dụng bản sao được lưu trong bộ nhớ cache?

từ các bản ghi máy chủ ...

Đầu tiên

(1.1ms) with cte_scoring as (
select 
users.id, users.name, users.email, 
(select Coalesce(sum(value),0) from answer_votes where (answer_votes.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) + 
(select Coalesce(sum(value),0) from best_answers where (best_answers.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) + 
(select Coalesce(sum(value),0) from contributions where (contributions.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) total_score 
from 
users 
where 
users.student = 'true') 

select id, 
name, 
email, 
total_score 
from cte_scoring 
order by total_score desc 
limit 5 

3rd

(1.8ms) with cte_scoring as (
select 
users.id, users.name, users.email, 
(select Coalesce(sum(value),0) from answer_votes where (answer_votes.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) + 
(select Coalesce(sum(value),0) from best_answers where (best_answers.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) + 
(select Coalesce(sum(value),0) from contributions where (contributions.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) total_score 
from 
users 
where 
users.student = 'true') 

select id, 
name, 
email, 
total_score 
from cte_scoring 
order by total_score desc 
limit 5 

Cập nhật

Các bản ghi hiển thị rằng nó được đọc một đoạn (sau khi truy vấn trên được chạy), vậy tại sao các truy vấn có thời gian khác nhau và truy vấn sau đó chậm hơn? Tôi đã có thể nghĩ rằng các truy vấn sẽ không được chạy ở tất cả nếu có một mảnh để đọc từ.

Read fragment views/id/75/name/Retarded Student/email/[email protected]/total_score/0/id/83/name/Jim Beam/email/[email protected]/total_score/0/id/79/name/Weird Student/email/[email protected]/total_score/0/id/80/name/VegetableSTudent/email/[email protected]/total_score/0/c9638e467bfd0fbf5b619ab411182256 (0.3ms) 
+0

Câu hỏi hay! Bộ nhớ đệm ActiveRecord dường như là rất nhiều bộ lạc truyền thuyết - tôi đã có một thời gian khó khăn tìm tài liệu rõ ràng để trả lời câu hỏi của bạn. – RyanWilcox

Trả lời

7

Cache kết quả truy vấn trong bộ điều khiển của bạn. Bạn có thể đọc hoặc ghi lại vào bộ nhớ cache trong một cuộc gọi (có nghĩa là, thiết lập các dữ liệu trong bộ nhớ cache nếu nó chưa tồn tại)

def index 
    @studentscoring = Rails.cache.fetch("your_cache_key", :expires_in => 5.minutes) do 
    ActiveRecord::Base.connection.select_rows(sql_string_student) 
    end 
end 

Vì vậy, ở trên đầu tiên sẽ kiểm tra bộ nhớ cache cho "your_cache_key" và nếu dữ liệu tồn tại sẽ trả về từ bộ nhớ cache. Nếu nó không tồn tại hơn khối sẽ thực hiện và nó sẽ được đặt trong bộ nhớ cache

+0

là bộ nhớ đệm hành động này? Nếu vậy, có đúng là nó không được đề xuất trong Rails 4? Dù bằng cách nào, là "your_cache_key" một cái gì đó tôi đặt tùy ý hoặc là nó đường ray tạo ra? Cảm ơn bạn đã giúp đỡ. – Leahcim

+0

khi tôi nói 'không được khuyến khích trong đường ray 4' tôi đã đề cập đến thực tế là bộ nhớ cache tiêu hóa đã được thêm vào để loại bỏ nhu cầu thiết lập số phiên bản của bộ đệm. Tôi không chắc nếu đó là những gì bạn đề cập đến với "your_cache_key" – Leahcim

+0

Đó không phải là thao tác lưu vào bộ nhớ cache –

7

Từ quan điểm bộ nhớ cache ActiveRecord:

Con đường tôi hiểu điều này là bộ nhớ cache truy vấn ActiveRecord là theo yêu cầu của web. Có nghĩa là nếu bạn chạy truy vấn SQL hai lần trong cùng một yêu cầu rằng nó sẽ sử dụng bộ nhớ cache, nhưng bộ đệm ẩn sẽ bị xóa ở cuối mỗi yêu cầu.

Nguồn: ActiveRecord::QueryCache middleware source

(Tôi tin rằng 'cuộc gọi ActiveRecord :: Base.execute được lưu trữ, nói chung, giống như yêu cầu của bạn với các API truy vấn ActiveRecord)

Nếu bạn chỉ muốn thực hiện truy vấn một lần cho vòng đời của ứng dụng (hoặc một lần trong vài giờ), bạn có thể sử dụng một API Rails khác: API lưu trữ để lưu bộ nhớ cache của bạn trên hệ thống tệp, trong bộ nhớ, trong memcache hoặc trong cửa hàng tùy chỉnh. The Rails Guide on Caching/Cache Stores.

Nếu bạn quyết định sử dụng Rails.cache, Heroku Dev Center on Caching Strategies có một số ví dụ về mã cho bạn biết API nào cho Rails.cache trông giống như thế. Nó khá dễ sử dụng.

Tại sao bộ nhớ cache đoạn không hoạt động như bạn mong đợi

Cuộc gọi bộ nhớ cache theo quan điểm của bạn có nghĩa là bạn đang xác định một bộ nhớ cache mảnh. (xem số Rails Guide on Caching/Fragment caching section). Thao tác này sẽ lưu vào đầu ra HTML theo dạng xem, như bạn thấy trong nhật ký của mình.

Nhưng bộ nhớ cache phân đoạn chỉ áp dụng cho HTML. Khi bạn thực hiện truy vấn của mình và gán kết quả cho @studentscoring, bạn đang thực hiện nó trong bộ điều khiển (phải không?) Trước khi khung nhìn thực thi.

Truy vấn ActiveRecord thường lười - thực thi bị trì hoãn cho đến khi dữ liệu thực sự cần thiết, như lặp lại các bản ghi - vì vậy mẹo của bạn có thể đã hoạt động khi sử dụng API truy vấn ActiveRecord. Tuy nhiên, tôi đoán rằng các truy vấn ActiveRecord::Base.execute không phải là lười. Tôi không thể chứng minh điều đó, nhưng đó là điều mà bạn có thể chạy thử nghiệm.

Vì vậy, bộ nhớ cache phân đoạn của bạn có thể được sử dụng, nhưng bạn đã trả giá cho truy vấn trong bộ điều khiển.

Các vấn đề liên quan