2014-11-20 43 views
1

我在我的數據庫中有三個表:值,鍵和來源。密鑰和來源都有很多值。源有一個名爲file_date的日期時間列。對於每個鍵,我必須選擇具有特定日期範圍(通常在兩年內)之間來源的所有值。並非該範圍內的所有日期都有來源,並非所有來源都有價值。我需要創建一個包含該範圍內所有值的數組。如何加快這些ActiveRecord查詢?

我在第一次試圖簡單地查詢整個源陣列一次,像這樣:

Value.where(key: 1, source: sources_array) 

然而,因爲有幾個值是零,它只是返回的記錄,在該日有一個值。

所以,現在我創建了一個包含該日期範圍之間所有源的數組。沒有信息來源的日子只有零。然後,對於每個鍵,我遍歷sources數組,返回與foo和source匹配的值。這顯然不理想,頁面加載大約需要7秒。

這裏是代碼:

sources.map do |source| 
    Value.where(source: source, key: key) 
end 

任何想法?

回答

0

如果您只需要檢索數據並獲取數組就可以生成單個SQL查詢。

output = [] 

sources.each do |source| 
    output << "select * from values where (source like #{source} and key like #{key})" 
end 

result = ActiveRecord::Base.connection.execute(output.join(" union ")).to_a 
+0

我得到了這個錯誤:'ActiveRecord :: StatementInvalid:PG :: SyntaxError:ERROR:內存耗盡在或接近「源」' – NJP 2014-11-20 20:11:45

+0

您可以嘗試更改「union」爲「union all」,引用此SE問題: http://dba.stackexchange.com/questions/42852/postgres-9-2-select-multiple-specific-rows-in-one-query 這似乎是在PostgreSQL中組合多個select查詢的常用方法。 – Ravenstine 2014-11-20 20:26:30

0

您的.map的大問題是它運行多個查詢,而不是一個查詢,包含所有您想要的結果。使用每個附加查詢,您都會將請求發送到數據庫並接收回應的開銷。你需要做的是以一種方式生成查詢,它返回全部你可能要查找的結果,然後處理任何分組或排序應用程序端。

+0

我試過了。如果找不到任何東西,我找不到任何會有ActiveRecord返回nil的東西。 – NJP 2014-11-20 19:12:25

+0

如果找不到任何東西,它應該返回一個相當於空數組的對象。您可以調用'.to_a'來獲取數組,或調用'.empty?',當沒有結果時它將返回true – 2014-11-20 20:29:28

+0

有結果,但源數組的值爲零(因爲沒有源那天)。 ActiveRecord只是忽略數組中的nil值。另外,還有一些來源對那天的密鑰沒有任何價值。 – NJP 2014-11-20 20:39:12

0

你可以嘗試在一個事務中包裝您的疑問:

ActiveRecord::Base.transaction do 
    sources.map do |source| 
    Value.where(source: source, key: key) 
    end 
end 
+0

我剛剛嘗試過,並且它仍然在7秒時鐘。 – NJP 2014-11-20 19:15:03

0

我需要重構這個像瘋了似的,但我有一些已經剪下來3秒:

source_ids = sources.map do |source| 
    if source 
     source.id 
    else 
     nil 
    end 
    end 

    values = Value.where(source: sources, key: key) 
    value_sources = values.pluck(:source_id) 
    value_decimals = values.pluck(:value_decimal) 

    source_ids.map do |id| 
    index = value_sources.index(id) 

    if index 
     value_decimals[index] 
    else 
     nil 
    end 
    end