2013-10-17 57 views
4

存在500000個產品ID的列表列表。我想從數據庫中獲取所有這些產品。使用dbContext.Products.Where(p => list.contains(p.ID))會在SQL中生成一個巨大的IN - WHERE ID IN (2134,1324543,5675,32451,45735...),並且它會持續使用。這部分是因爲SQL Server解析這麼大的字符串需要時間,而且執行計劃也不好。 (我知道這是從嘗試使用臨時表代替)。參考實體框架查詢中的臨時表

所以我用使用SqlBulkCopy的標識插入到一個臨時表,然後跑去

dbContext.Set<Product>().SqlQuery("SELECT * FROM Products WHERE ID IN (SELECT ID FROM #tmp))" 

這給了良好的性能。但是,現在我需要產品和他們的供應商(每種產品都有多個產品)。使用自定義SQL命令無法找回我知道的複雜對象。那麼,如何使用臨時表格與供應商取得產品呢? (如果我可以以某種方式在LINQ中引用臨時表,那麼它就可以 - 我可以做dbContext.Products.Where(p => dbContext.TempTable.Any(t => t.ID==p.ID))。如果我可以在UDF中引用它,那也是好的 - 但你不能。我不能用一個真正的表,因爲併發用戶將它留在不一致的狀態。)

感謝

+0

你可以使用一個真正的表,其中有一個'userid'的列 – qujck

+0

你意思是ProductID?最後我已經提到過這種可能性。 – wezten

+2

如果您在過濾表(TempTable)中包含用戶標識或其他區分字段,那麼您將不會遇到併發用戶的問題。 – qujck

回答

1

我建議你延長過濾器表(TempTable在上面的代碼)來存儲就像一個UserIdSessionId以及ProductID's

  • 這會給你所有你以後
  • 它將爲併發用戶

工作,如果這個過濾器表變化的話,很多考慮在單獨的事務更新它的性能(即一個不同的dbContext實例),以避免在此表上保留一個寫鎖定的時間超過必要的時間。

2

我很好奇探索使用Join語法生成的sql而不是Contains。下面是我的測試代碼:

IQueryable<Product> queryable = Uow.ProductRepository.All; 
List<int> inMemKeys = new int[] { 2134, 1324543, 5675, 32451, 45735 }.ToList(); 
string sql1 = queryable.Where(p => inMemKeys.Contains(p.ID)).ToString(); 

string sql2 = queryable.Join(inMemKeys, t => t.ID, pk => pk, (t, pk) => t).ToString(); 

這是使用生成的SQL包含:(SQL1)

SELECT 
    [extent1].[id] AS [id],...etc 
FROM [dbo].[products] AS [extent1] 
WHERE ([extent1].[id] IN (2134, 1324543, 5675, 32451, 45735)) 

這是生成的SQL使用加入:

SELECT 
    [extent1].[id] AS [id],...etc 
FROM [dbo].[products] AS [extent1] 
    INNER JOIN (SELECT 
     [unionall3].[c1] AS [c1] 
    FROM (SELECT 
     [unionall2].[c1] AS [c1] 
    FROM (SELECT 
     [unionall1].[c1] AS [c1] 
    FROM (SELECT 
     2134 AS [c1] 
    FROM (SELECT 
     1 AS x) AS [singlerowtable1] UNION ALL SELECT 
     1324543 AS [c1] 
    FROM (SELECT 
     1 AS x) AS [singlerowtable2]) AS [unionall1] UNION ALL SELECT 
     5675 AS [c1] 
    FROM (SELECT 
     1 AS x) AS [singlerowtable3]) AS [unionall2] UNION ALL SELECT 
     32451 AS [c1] 
    FROM (SELECT 
     1 AS x) AS [singlerowtable4]) AS [unionall3] UNION ALL SELECT 
     45735 AS [c1] 
    FROM (SELECT 
     1 AS x) AS [singlerowtable5]) AS [unionall4] 
     ON [extent1].[id] = [unionall4].[c1] 

所以SQL使用union all創建一個大的select語句來創建臨時表的等價物,然後它加入到該表中。 sql比較冗長,但它可能很有效 - 恐怕我沒有資格說。

雖然它沒有回答標題中列出的問題,但確實顯示了避免巨人IN的方法。好吧....現在這是一個巨大的UNION ALL ....反正...我希望這個貢獻對一些有用