2012-02-16 32 views
6

Tôi đang nhập bản ghi hàng loạt và không muốn cập nhật bộ đếm mỗi lần. Tôi muốn bỏ qua các cập nhật sql của counter_cache trong quá trình upsert số lượng lớn, sau đó gọi reset_counters ở cuối vòng lặp.Cách tắt counter_cache liên kết Rails tại thời gian chạy

Tôi đã thử:

my_model = MyModel.find_or_initialize_by_slug row[:slug] 
my_model.association(:my_association).reflection.options[:counter_cache] = false 
my_model.attributes = {:name => "Christopher"} 
my_model.save! 

nhưng tôi có thể nhìn thấy trong đầu ra sql mà nó vẫn cập nhật counter_cache.

lưu ý: Tôi không thể sử dụng activerecord-nhập khẩu bởi vì tôi muốn thực hiện upserts và tôi đang sử dụng postgresql

+0

Bạn đã giải quyết vấn đề này chưa? Cùng một vấn đề ... –

Trả lời

5

Bạn có một vài tùy chọn khác nhau cho bỏ qua một bản cập nhật của bộ nhớ cache truy cập, và một trong đó bạn chọn thực sự phụ thuộc vào cách bạn muốn cấu trúc ứng dụng của mình. Tôi sẽ thảo luận về những cách khác nhau mà bạn có thể nhận được xung quanh bộ nhớ cache truy cập và đề cập đến một số trong những cân nhắc bạn có thể muốn thực hiện khi làm như vậy.

Về cơ bản, có ba cách khác nhau mà bạn có thể bỏ qua các bản cập nhật của bộ nhớ cache truy cập:

  1. Monkey patch your model to disable the counter cache callback
  2. Use an update method that doesn't trigger callbacks
  3. Xác định một mô hình trỏ thay thế cho cùng một bảng mà không có cùng một hành vi gọi lại và sử dụng hành vi đó khi chèn hàng loạt vào cơ sở dữ liệu

Lưu ý rằng hai tùy chọn đầu tiên ở trên là g liên quan đến việc vô hiệu hóa các cuộc gọi lại trong ActiveRecord và điều này có ý nghĩa vì bộ đệm truy cập được thực hiện nội bộ bằng phương thức gọi lại.

Khi Rails tải một mô hình có các liên kết với bộ đệm truy cập, nó định nghĩa động các phương thức gọi lại. Nếu bạn muốn vô hiệu hóa chúng như một cuộc gọi lại, trước tiên bạn phải tìm ra tên gọi lại là gì.

Có hai cách chính để tìm ra phương pháp mà Rails đã xác định để thực hiện các cuộc gọi lại này. Bạn có thể đọc nguồn Rails để tìm ra các tên mà nó sẽ tạo ra thông qua sự tích hợp chuỗi, hoặc bạn có thể sử dụng nội tâm để tìm ra phương thức mà lớp của bạn đáp ứng. Tôi sẽ đưa ra một ví dụ về cách bạn có thể sử dụng nội tâm để tìm ra các callback được định nghĩa bởi ActiveRecord để tự động thực hiện bộ nhớ đệm truy cập.

Giả sử bạn có một lớp được gọi là SpecialReply xuống từ lớp Trả lời xuống từ ActiveRecord :: Base (this example comes from the test suite with Rails). Nó có có một cột truy cập bộ nhớ cache theo quy định dưới đây:

class SpecialReply < ::Reply 
    belongs_to :special_topic, :foreign_key => 'parent_id', :counter_cache => 'replies_count' 
end 

Trong giao diện điều khiển, bạn có thể xem những gì các phương pháp lớp học của bạn đáp lại bằng cách sử dụng .methods. Điều này sẽ tạo ra rất nhiều tiếng ồn, vì mỗi thể hiện của Object đã đáp ứng rất nhiều phương pháp, vì vậy bạn có thể thu hẹp danh sách như sau:

1.9.3-p194 :001 > sr = SpecialReply.new 
1.9.3-p194 :002 > sr.methods - Object.methods 

Trên dòng thứ hai bạn đang nói, show tôi tất cả các phương pháp mà trường hợp của tôi SpecialReply phản ứng, trừ đi những đối tượng mà tất cả các đối tượng phản hồi. Điều này thường giúp ích cho việc tìm kiếm bằng cách lọc ra các phương thức không dành riêng cho loại lớp mà bạn đang xem.

Thật không may ngay cả sau khi bộ lọc này có nhiều tiếng ồn do các phương thức mà ActiveRecord thêm vào tất cả các lớp con cháu của nó. Trong trường hợp này grep rất hữu ích - kể từ ActiveRecord helpfully tạo ra các phương thức callback truy cập có chứa String counter_cache (see the meta-programming used by ActiveRecord to generate a counter cache method for a belongs_to association), bạn có thể tìm hiểu các callbacks được xác định liên quan để đối phó với bộ nhớ đệm như sau:

1.9.3-p194 :001 > sr = SpecialReply.new 
1.9.3-p194 :002 > sr.methods.map(&:to_s).grep(/counter_cache/) 

Chú ý rằng kể từ khi grep hoạt động trên một String, và methods trả về một mảng các tên phương thức biểu tượng, trước tiên chúng ta sử dụng to_proc (&:) để chuyển đổi tất cả các ký hiệu thành chuỗi và sau đó grep ra các ký tự có chứa counter_cache. Điều này khiến tôi với các phương pháp sau đây mà dường như họ có lẽ tính năng tự động tạo ra bởi ActiveRecord như callbacks để thực hiện truy cập bộ nhớ đệm:

belongs_to_counter_cache_after_create_for_special_topic 
belongs_to_counter_cache_before_destroy_for_special_topic 
belongs_to_counter_cache_after_create_for_topic 
belongs_to_counter_cache_before_destroy_for_topic 
belongs_to_counter_cache_after_create_for_topic_with_primary_key 
belongs_to_counter_cache_before_destroy_for_topic_with_primary_key 

Bạn sẽ có thể thực hiện theo một quá trình tương tự trong chương trình của bạn để xác định tên phương pháp bổ sung bởi ActiveRecord để bạn có thể loại bỏ chúng sau existing instructions for removing callbacks.

Lựa chọn của bạn từ các tùy chọn ở trên thực sự phụ thuộc vào cấu trúc chương trình của bạn và sự cân bằng mà bạn sẵn sàng cân nhắc để tăng hiệu quả tải dữ liệu. Đáng lưu ý là hai tùy chọn đầu tiên có thể làm cho mã của bạn ít có thể đọc được bằng cách sửa đổi hành vi của lớp từ bên ngoài (vá khỉ) và có thể làm cho hệ thống của bạn không ổn định bằng cách bỏ qua các quy tắc nghiệp vụ (cập nhật các cột bộ nhớ cache) về cập nhật dữ liệu. Vì những lý do này, tôi sẽ suy nghĩ về việc liệu bạn có thể tạo một lớp khác để tải dữ liệu của bạn một cách tối ưu hóa trong khi giảm thiểu tác động đến khả năng đọc hoặc tính nhất quán của dữ liệu.

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