سؤال

لدي شجرة من كائنات السجل النشطة، مثل:

class Part < ActiveRecord::Base
  has_many :sub_parts, :class_name => "Part"

  def complicated_calculation
    if sub_parts.size > 0
      return self.sub_parts.inject(0){ |sum, current| sum + current.complicated_calculation }
    else
      sleep(1)
      return rand(10000)
    end
  end

end

إن إعادة حساب الحساب المعقد في كل مرة أمر مكلف للغاية.لذا، أحتاج إلى طريقة لتخزين القيمة مؤقتًا.ومع ذلك، إذا تم تغيير أي جزء، فإنه يحتاج إلى إبطال ذاكرة التخزين المؤقت الخاصة به وذاكرة التخزين المؤقت الخاصة بالأصل والأجداد، وما إلى ذلك.

كمسودة تقريبية، قمت بإنشاء عمود للاحتفاظ بالحسابات المخزنة مؤقتًا في جدول "الأجزاء"، ولكن هذه الرائحة فاسدة بعض الشيء.يبدو أنه يجب أن تكون هناك طريقة أنظف لتخزين القيم المحسوبة مؤقتًا دون حشوها بجانب الأعمدة "الحقيقية".

هل كانت مفيدة؟

المحلول

  1. يمكنك تعبئة القيم المخزنة مؤقتًا فعليًا في ذاكرة التخزين المؤقت لـ Rails (استخدم memcached إذا كنت تريد توزيعها).

  2. الشيء الصعب هو انتهاء صلاحية ذاكرة التخزين المؤقت، ولكن انتهاء صلاحية ذاكرة التخزين المؤقت غير شائع، أليس كذلك؟في هذه الحالة، يمكننا فقط تكرار كل كائن من الكائنات الأصلية على حدة وتنشيط ذاكرة التخزين المؤقت الخاصة به أيضًا.لقد أضفت بعض سحر ActiveRecord إلى صفك لتسهيل عملية الحصول على الكائنات الأصلية - ولا تحتاج حتى إلى لمس قاعدة البيانات الخاصة بك.تذكر أن تتصل Part.sweep_complicated_cache(some_part) حسب الاقتضاء في التعليمات البرمجية الخاصة بك - يمكنك وضع هذا في عمليات رد الاتصال، وما إلى ذلك، ولكن لا يمكنني إضافتها لك لأنني لا أفهم متى complicated_calculation يتغير.

    class Part < ActiveRecord::Base
      has_many :sub_parts, :class_name => "Part"
      belongs_to :parent_part, :class_name => "Part", :foreign_key => :part_id
    
      @@MAX_PART_NESTING = 25 #pick any sanity-saving value
    
      def complicated_calculation (...)
        if cache.contains? [id, :complicated_calculation]
          cache[ [id, :complicated_calculation] ]
        else
          cache[ [id, :complicated_calculation] ] = complicated_calculation_helper (...)
        end
      end
    
      def complicated_calculation_helper
        #your implementation goes here
      end
    
      def Part.sweep_complicated_cache(start_part)
        level = 1  # keep track to prevent infinite loop in event there is a cycle in parts
        current_part = self
    
        cache[ [current_part.id, :complicated_calculation] ].delete
        while ( (level <= 1 < @@MAX_PART_NESTING) && (current_part.parent_part)) {
         current_part = current_part.parent_part)
         cache[ [current_part.id, :complicated_calculation] ].delete
        end
      end
    end
    

نصائح أخرى

وأنا أقترح استخدام الاسترجاعات الجمعيات.

class Part < ActiveRecord::Base
  has_many :sub_parts,
    :class_name => "Part",
    :after_add => :count_sub_parts,
    :after_remove => :count_sub_parts

  private

  def count_sub_parts
    update_attribute(:sub_part_count, calculate_sub_part_count)
  end

  def calculate_sub_part_count
    # perform the actual calculation here
  end
end

ونيس وسهلة =)

هل لديك حقل مشابه لما مخبأ العداد. على سبيل المثال: order_items_amount ولها أن تكون حقل محسوب مؤقتا.

استخدم مرشح after_save لإعادة حساب الحقل على أي شيء يمكن تعديل تلك القيمة. (بما في ذلك سجل نفسه)

وتحرير: هذا هو أساسا ما لديك الآن. أنا لا أعرف من أي حل أنظف إلا إذا أردت تخزين الحقول المحسوبة مؤقتا في جدول آخر.

وإما باستخدام before_save أو مراقب أكتيفيريكورد هو الطريق للذهاب للتأكد من القيمة المخزنة مؤقتا هو ما يصل إلى التاريخ. أود أن استخدام before_save ثم تحقق لمعرفة ما إذا كانت القيمة التي تستخدم في حساب تغيرت بالفعل. وبهذه الطريقة لم يكن لديك لتحديث ذاكرة التخزين المؤقت إذا لم يكن في حاجة إليها.
سوف تخزين القيمة في ديسيبل تسمح لك لتخزين الحسابات على طلبات متعددة. وثمة خيار آخر لذلك هو لتخزين قيمة في memcache. يمكنك جعل استرجاع خاص واضع لأن القيمة التي يمكن أن تحقق في memcache وتحديثه إذا لزم الأمر.
فكرة أخرى: هل تكون هناك حالات حيث ستتمكن من تغيير قيمة في واحد من النماذج وتحتاج حساب ليتم تحديثه قبل أن تفعل حفظ؟ في هذه الحالة سوف تحتاج إلى القذرة قيمة مخبأ كلما قمت بتحديث أي من القيم الحسابية في النموذج، وليس مع before_save.

ولقد وجدت أنه في بعض الأحيان هناك سبب وجيه لنزع تطبيع المعلومات في قاعدة البيانات الخاصة بك. لدي شيئا من هذا القبيل في أحد التطبيقات التي أنا أعمل على وأنا فقط إعادة حساب هذا المجال في أي وقت التغييرات المجموعة.

وأنها لا تستخدم ذاكرة التخزين المؤقت وأنه يخزن معظم ما يصل إلى الرقم حتى الآن في قاعدة البيانات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top