2015-02-08 54 views
4

我正在使用EF6,我想要獲得一組ID中的記錄。這是不是比這更好?

在我的測試例如我使用4個ID。

我嘗試了兩種選擇,第一種是與任何選項。

dbContext.MyTable 
.Where(x => myIDS.Any(y=> y == x.MyID)); 

而且這種LINQ exrepsion產生的T-SQL是:

SELECT 
    * 
    FROM [dbo].[MiTabla] AS [Extent1] 
    WHERE EXISTS (SELECT 
     1 AS [C1] 
     FROM (SELECT 
      [UnionAll2].[C1] AS [C1] 
      FROM (SELECT 
       [UnionAll1].[C1] AS [C1] 
       FROM (SELECT 
        cast(130 as bigint) AS [C1] 
        FROM (SELECT 1 AS X) AS [SingleRowTable1] 
       UNION ALL 
        SELECT 
        cast(139 as bigint) AS [C1] 
        FROM (SELECT 1 AS X) AS [SingleRowTable2]) AS [UnionAll1] 
      UNION ALL 
       SELECT 
       cast(140 as bigint) AS [C1] 
       FROM (SELECT 1 AS X) AS [SingleRowTable3]) AS [UnionAll2] 
     UNION ALL 
      SELECT 
      cast(141 as bigint) AS [C1] 
      FROM (SELECT 1 AS X) AS [SingleRowTable4]) AS [UnionAll3] 
     WHERE [UnionAll3].[C1] = [Extent1].[MiID] 
    ) 

怎樣才能被看到,T-SQL是一種 「地方存在」 使用子查詢很多和工會。

第二個選項是包含。

dbContext.MyTable 
.Where(x => myIDS.Contains(x.MiID)); 

和T-SQL:

SELECT 
    * 
    FROM [dbo].[MiTabla] AS [Extent1] 
    WHERE [Extent1].[MiID] IN (cast(130 as bigint), cast(139 as bigint), cast(140 as bigint), cast(141 as bigint)) 

將包含被翻譯成 「在」,但查詢是簡單得多。

我已經讀過,任何它使用更快,所以我懷疑,如果任何是,雖然它乍一看更復雜,更快或沒有。

非常感謝。

編輯:我有一些測試(我不知道這是測試這個最好的方法)。

System.Diagnostics.Stopwatch miswContains = new System.Diagnostics.Stopwatch(); 
         miswContains.Start(); 
         for (int i = 0; i < 100; i++) 
         { 
          IQueryable<MyTable> iq = dbContext.MyTable 
          .Where(x => myIDS.Contains(x.MyID)); 

          iq.ToArrayAsync(); 
         } 
         miswContains.Stop(); 



         System.Diagnostics.Stopwatch miswAny = new System.Diagnostics.Stopwatch(); 
         miswAny.Start(); 
         for (int i = 0; i < 20; i++) 
         { 
          IQueryable<MyTable> iq = dbContext.Mytable 
          .Where(x => myIDS.Any(y => y == x.MyID)); 

          iq.ToArrayAsync(); 
         } 
         miswAny.Stop(); 

結果是miswAny約爲850ms,miswContains約爲4251ms。

所以第二個選擇,contaions,更慢。

+0

'Entity Framework'用'select *'生成代碼?長類型的ID是多少?你怎麼知道結果是否沒有被緩存,你是否嘗試交換查詢順序? – Ofiris 2015-02-08 20:10:08

回答

2

如果您的MiTabla.MiID索引中,您的第二個選項是我能想到的最快解決方案(至少對於非常大的ID數組)。

如果您想了解更多關於in子句性能:Is SQL IN bad for performance?

+0

我已編輯原始帖子以添加測試。但我不知道這是否是測試這種情況的最佳方式。 – 2015-02-08 20:01:44

+1

不,這不是,因爲你沒有考慮到一些外部因素,如SQL緩存或淨延遲,雖然它可能會給你一個粗略的估計。無論如何,你迭代20次做第二次測試,100次做第一次測試(結果顯示它快5倍,可能是由於這個原因)。此外,您應該可能使用await指令'iq.ToArrayAsync()' – Joanvo 2015-02-09 13:51:51

+0

謝謝,我沒有意識到我正在使用異步方法。 – 2015-02-09 19:30:58

1

如果你知道ID,然後使用LINQ2SQL計數()方法將創建一個更清潔和更快的SQL代碼(除雙方的任何及包含):

dbContext.MyTable 
.Where(x => myIDS.Count(y=> y == x.MyID) > 0); 

爲計數看起來應該生成的SQL像這樣:

DECLARE @p0 Decimal(9,0) = 12345 
SELECT COUNT(*) AS [value] 
FROM [ids] AS [t0] 
WHERE [t0].[id] = @p0 
+0

我知道這種情況下的ID。但是當我有很多ID時,這將是怎麼回事? – 2015-02-08 20:06:59

+1

您檢查匹配計數 - 如果計數爲正數(至少爲1,如果ID不唯一),則ID列表包含指定的ID。 – pasty 2015-02-08 20:13:44

1

您可以通過查詢該Any是不能擴展在所有的形狀出來。在myIDS(大概50)中,並不需要很多元素才能獲得最大嵌套級別已超出的SQL異常。

Contains在這方面好得多。在性能受到嚴重影響之前,它可以處理數千個元素。

所以我會選擇可擴展的解決方案,儘管Any可能會比較小,但速度更快。有可能製造Contains甚至better scalable

我已閱讀,任何使用它要快,

在LINQ到對象是一般真實的,因爲枚舉停止在第一次打擊。但是,LINQ針對SQL後端,生成的SQL是重中之重。