2011-08-03 2 views
4

많은 레이크 작업 (상인이라고 함)을 통해 반복적으로 작업해야하는 레이크 작업이 있습니다. 내 문제는 레일스가 자동으로 DB 쿼리 결과를 캐싱하기 때문에 결국에는 스태프 공간에 작업자를 배치하기 시작합니다. '항목'을 통해 각 시간의 값을 캐싱하지 않고레일즈가 ActiveRecord 쿼리 결과를 캐시하지 못하도록하기

Merchant.all.each { |m| items = m.items }

: 한마디로

, 나는 같은 명령을 실행하는 방법을 궁금하네요.

Merchant.all.each do |m|` 
    ActiveRecord::Base.connection.uncached do 
    items = m.items 
end 
end 

나는 또한 나의 상인 모델이 추가 시도했다 : :

나는 해봤 대신 items_uncached 호출 후

def items_uncached 
    self.class.uncached { items } 
end 

하고,하지만, 난 여전히까지 건 드리는 결국 내가 액세스하는 각각의 새로운 항목 세트로 메모리 사용량.

저는 레일즈 2.3.10, 루비 1.9.2를 실행 중이며 저장소에 MySQL을 사용하고 있습니다.

미리 감사드립니다.

* 편집 :

여기에 내가 일하고 있어요 코드의 실제 비트입니다 :

File.open(output, "w") do |f| 
    Merchant.all.each do |m| 
    items = m.items 
    invalid_image_count = 0 
    items.each do |i| 
     invalid_image_count += 1 unless i.image_valid? 
    end 
    invalid_categories = items.select { |i| !i.categories_valid? }.count 
    f.puts "#{m.name} (#{m.id}): #{invalid_image_count} invalid images, " + 
      "#{invalid_categories} invalid categories" 
    end 
end 

일부 오류 검사를 수행하려고 한 후 그 결과를 기록.

+1

여기서 수행하려는 작업은 분명하지 않습니다. 어쩌면 당신은 ActiveRecord :: Base # find_each와 같은 것을 찾고 있습니까? – coreyward

+0

좋아요, 예. find_each를 보았는데 실제로 도움이 될 수 있습니다. 시도해 볼게. – peter

+0

콘솔에서이 코드를 실행하면 조금 더 잘 표현할 수 있습니다. Merchant.all.each {| m | items = m.items; print "# {m.id}"}, 각 반복마다 내 메모리 사용량에 문제가 있습니다. 내 추측으로 이것은 m.items가 1에서 10,000+ ActiveRecords 사이에서 발생한다는 사실 때문이었습니다. – peter

답변

3

당신의 관계는 당신이 시도 할 수있는 간단한 has_many 한 경우 :

Merchant.all.each do |m| 
    items = Item.find_all_by_merchant_id(m.id) 
    ... 
end 

심지어 :

Merchant.find(:all, :select => "id, name").each do |m| 
    items = Item.find_all_by_merchant_id(m.id) 
    ... 
end 
+0

이것이 캐싱을 피하는 지 확실하지 않습니다. 그것은 간단한 has_many 관계지만,이 경우 m.items는 Item.find_all_by_merchant_id (m.id)와 동일한 결과/반환 값을 가져야한다고 생각합니다. 그게 옳은가요? – peter

+0

'm.items'는'Merchant.all' 배열을 해제 할 때까지 (즉,'each' 루프가 끝날 때까지) 릴리스 될 것입니다. 제 경우에는'items'가 해제되고 재 할당 후에 가비지 수집됩니다 다음의'each' 반복. –

+0

예 예 예. 방금 내 마음을 날려 버렸어. 고맙습니다. – peter

4

쿼리 캐시가 여기에 주요 문제가되지 않습니다가. 레일스는 어쨌든 개체를 "캐시"합니다.

쿼리 캐시는 레일스가 DB를 불필요하게 때리는 것을 방지하는 "해시 조회"이며, 루비 (또는 레일스)가 내부적으로 연관에 의해 반환 된 개체를 저장하는 방법을 제어하지 않습니다. 당신은 단순히 모든 항목 모든 Merhcant 인스턴스를 채우는 당신의 each 루프 그래서 지금 당신이 m.items을 수행 할 때

m = Merhant.first # <- m is loaded from DB 
m.items   # <- items are loaded from DB and STORED(!) in m 
m.items   # <- items are returned from the association stored in m 
m.items.reload # <- hits the DB (or the query cache) 
m.instance_variable_get("@items") # <- returns the actual stored items 

을하고, 가비지 컬렉터는 할 수 없습니다 :

예를 들어이 (심지어 캐시되지 않은 경우) 시도 루프 내부에있는 동안 모든 객체가 all 배열에서 참조되므로 아무 것도 무료로 사용할 수 있습니다.

그래서 해결책은 빅터가 제안한 것처럼 "연관 저장소"가 트리거되지 않도록하는 것입니다.

+0

고맙습니다. 이제 이해가된다 :) – peter

관련 문제