2012-02-03 12 views
5

मैं अपने एसोसिएशन के साथ एक ActiveRecord को कैश करने की कोशिश कर रहा हूं। समस्या पुनर्प्राप्त रिकॉर्ड पर एसोसिएशन तक पहुंचने पर डेटाबेस क्वेरी है।कैशिंग सीमित एसोसिएशन

आम तौर पर, मैं केवल उत्सुक लोडिंग Rails.cache.write('post', Post.includes(:comments).find(99)) के साथ कैश करता हूं। ऐसा लगता है, लेकिन समस्या यह है कि मैं केवल एसोसिएशन के सीमित सबसेट को कैश करना चाहता हूं, और उत्सुक लोडिंग के दौरान सीमाएं अनदेखा की जाती हैं (उदाहरण के लिए here का उल्लेख किया गया है)। तो Post.includes(:popular_comments).find(99)सभी टिप्पणियां, केवल लोकप्रिय लोगों को नहीं लौटाएगा।

तो मैं आलसी लोड संघ के बाद वस्तु कैशिंग की कोशिश की है, लेकिन जब बाहर वस्तुओं खींच एक प्रश्न दुर्भाग्य से होती है:

class Post < ActiveRecord::Base 
    has_many :comments 
    has_many :popular_comments, :class_name > 'Comment', :limit => 20, :order => :votes 

post = Post.find(99) 
post.popular_comments # lazy-load limited associations 
Rails.cache.write('post', post) 
... 
Rails.cache.read('post').popular_comments # Unwanted SQL query :(

मैं बजाय एक क्लोन कैशिंग की कोशिश की है, एक ही अवांछित SQL क्वेरी । और मैंने रेडिस और memcached कार्यान्वयन दोनों के साथ यह कोशिश की है, एक ही परिणाम। विचित्र रूप से, यह अनुक्रम कंसोल afaict पर काम करता है, लेकिन एक नियंत्रक में एक सरल उपयोग या ऊपर की तरह दृश्य विफल रहता है (यानी एसक्यूएल होता है)।

अद्यतन (अप्रैल 2017): अब मैं कहूंगा कि यह एक मूर्ख आधार है। पूरी वस्तुओं को कैशिंग करना आम तौर पर अपर्याप्त होता है क्योंकि यह बहुत सारे कैश स्टोरेज का उपयोग करता है और यह धारावाहिक/deserialise करने के लिए धीमा है। कैशिंग एसोसिएशन भी (जैसा कि इस प्रश्न में पूछा गया है) एन द्वारा बर्बाद कर रहा है। आमतौर पर कच्चे आईडी और एचटीएमएल टुकड़े को कैश करने के लिए यह अधिक कुशल है।

+0

रेल के कौन से संस्करण आप चल रहे हैं? – Brandan

+0

@ ब्रैंडन यह रेल पर है 3.1 – mahemoff

+0

क्या आप लॉग का एक स्निपेट पोस्ट कर सकते हैं जो दिखा रहा है कि SQL क्या निष्पादित हो रहा है और अनुरोध में यह कहां हो रहा है? मैं इसे पुन: पेश नहीं कर सका। – Brandan

उत्तर

6

post.popular_comments.reload

सबसे पहले कोशिश करें, सीमा वास्तव में अनदेखी कर रहे हैं जब उत्सुक लोड हो रहा है। the docs से:

If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects

इसका मतलब यह है, जैसे आप की खोज की, आप अपने आप को आपत्ति जनक में संघ के लिए मजबूर करने की है। मेरे प्रयोगों में, post.popular_comments काम नहीं किया (यह समझ में आता है, क्योंकि यह प्रॉक्सी ऑब्जेक्ट देता है), और दिलचस्प रूप से न तो post.popular_comments.all किया। post.popular_comments(true) हालांकि चाल है। उस कोड के नीचे रीलोड कॉल करता है, और बस post.popular_comments.reload को भी पेरेंट क्लास में एसोसिएशन लोड किया जाता है।

मुझे यकीन नहीं है कि इनमें से कौन सा अधिक सही है, post.popular_comments(true) या post.popular_comments.reload। दोनों थोड़ा भंगुर लगते हैं, लेकिन दूसरा एक अच्छा पढ़ता है और आपके इरादे को और स्पष्ट रूप से व्यक्त करता है।

मैं पुष्टि है कि इन दोनों तरीकों:

  1. मेम्कैश
  2. में सीमित संघ संग्रहित कैश से

मेरे स्क्रिप्ट लोड पद स्टोर करने के लिए के बाद एक SQL क्वेरी को ट्रिगर नहीं किया:

require 'pp' 
Rails.cache.clear 
post = Post.first 

#post.popular_comments(true) 
post.popular_comments.reload 

Rails.logger.info "writing to cache" 
s = Rails.cache.write "post", post 
Rails.logger.info "writing to cache done" 

और पुनर्प्राप्त करने के लिए:

require 'pp' 
Rails.logger.info "reading from cache" 
post = Rails.cache.read "post" 
Rails.logger.info "reading from cache done" 
Rails.logger.info post.popular_comments.inspect 

अगर मैं दूसरे मेरी लॉग शो के बाद एक चलाएँ:

Post Load (0.5ms) SELECT `posts`.* FROM `posts` LIMIT 1 
    Comment Load (0.5ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 1 ORDER BY votes LIMIT 20 
writing to cache 
writing to cache done 
reading from cache 
reading from cache done 
[#<Comment id: 1, ... 

मेरे mySQL लॉग भी पुष्टि की है कि दूसरे पटकथा सहयोग के लिए एक प्रश्न ट्रिगर नहीं करता।

इस रेल 3.1.1

+0

ग्रेट, उत्तर, धन्यवाद। मैं अभी इसका परीक्षण नहीं कर सकता, लेकिन आप समस्या को समझ चुके हैं और यह सबसे अच्छा संभव समाधान की तरह लगता है। – mahemoff

0

मुझे आपके परीक्षणों में वर्णित समस्या को नहीं देख रहा है।

कोड है कि मैं नियंत्रक में इस्तेमाल किया है

def show 
    unless Rails.cache.exist?('faq_category') 
    @faq_category = Faq::Category.first 
    @faq_category.questions 
    Rails.cache.write('faq_category', @faq_category) 
    end 
    @faq_category = Rails.cache.read('faq_category') 
end 

जब मैं पेज मैं लॉग में निम्न कथनों को देखने जो कहता है कि मॉडल https://skitch.com/aroop/g9w5t/untitled

पर enter image description here बड़ी छवि उपलब्ध पुनः लोड नहीं हो रहे हैं चलाने

समस्या आपकी दृश्य फ़ाइल के साथ हो सकती है। दृश्य पर टिप्पणी करें और देखें कि समस्या अभी भी है या नहीं।

+0

यह एक मुद्दा है जिसे मैं देख रहा हूं कि has_many एसोसिएशन सीमित है। मैंने सवाल में और जानकारी डाली है। – mahemoff

+1

मुझे एक पल मिलने पर मैं आपकी स्थिति को अनुकरण करने की कोशिश करूंगा –

+0

बहुत धन्यवाद। यह जटिल नहीं होना चाहिए। एसोसिएशन पर परिभाषित सीमा के साथ बस एक है_मैनी एसोसिएशन। – mahemoff

0

रेल 5 साथ किया गया था सब पर समर्थन नहीं करता :limit => 20 विकल्प। आप त्रुटि के नीचे मिल जाएगा:

ArgumentError: Unknown key: :limit. Valid keys are: :class_name, :anonymous_class, :foreign_key, :validate, :autosave, :table_name, :before_add, :after_add, :before_remove, :after_remove, :extend, :primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache, :join_table, :foreign_type, :index_errors

आप स्पष्ट रूप से post.popular_comments.limit(20) उपयोग करना होगा।

संबंधित मुद्दे