2010-08-05 24 views
1

這是LINQ to DB2問題的下一步,我問here性能問題 - 大型DLL和大型命名空間

跟着zb_z的回答,我探索了一下DB_Linq的代碼,並設法增加了對DB2的支持。 (它現在還處於初級階段,還沒有準備好回饋給項目。)概念證明的效果很好,實際上它非常令人興奮。但是,我一路上遇到了另一個呃逆。

事實證明,我們的DB2數據庫是big。 8,306桌大。所以生成的代碼竟然超過了520萬行代碼。在一個文件中。毋庸置疑,Visual Studio並沒有太在意:) :)

所以我進一步修改了生成器以便將每個表類放到它自己的文件中。這給我留下了8307個文件(數據上下文和每個表的一個,它們擴展了帶有表屬性的數據上下文)。 Visual Studio仍然不喜歡它,可以理解,所以我將代碼生成和編譯包裝在一個腳本中,然後運行它輸出一個DLL供我的項目使用。

一個36 MB的DLL。

現在,在性能上搜索一下,導致我找到了this SO question(本身引用this one),我已經按照答案和鏈接查看他們在說什麼。因此,這讓我想知道它是否存在相同命名空間內的8000多個類,這是造成顯着性能問題的罪魁禍首。我對性能的測試是編寫一個小小的控制檯應用程序,它初始化數據上下文,用LINQ抓取數據,打印出行數,用傳統的ADO抓取數據,並打印出另一行數。每個陳述包括一個時間戳。添加更多查詢以進行測試等始終可獲得相同的性能。 LINQ代碼需要幾秒鐘的時間才能運行,而ADO則在一眨眼的時候填充數據集。

所以我猜這最終是一個有點開放式(並且冗長的,對此感到抱歉)的問題。有人有任何想法來加速表現嗎?任何簡單的調整,或我可以適用的設計考慮?

編輯

有幾件事情需要注意:

  1. 如果我限制代碼生成表(比如,200)的一個子集,然後運行更快。
  2. 在調試器中逐步調試,時間長度花費在行var foo = from t in bank1.TMX9800F where t.T9ADDEP > 0 select t.T9ADDEP上,並且當我在調試器中展開屬性以枚舉結果(或讓它進入執行.Count())的下一行時那部分根本沒有時間。

編輯

我不能發佈整個生成的DLL,但這裏的測試程序的代碼:也許我失去了一些東西明顯

static void Main(string[] args) 
     { 
      Console.WriteLine(string.Format("{0}: Process Started", DateTime.Now.ToLongTimeString())); 

      // Initialize your data contexts 
      var bank1 = new BNKPRD01(new iDB2Connection(ConfigurationManager.ConnectionStrings["DB2"].ConnectionString)); 
      var bank6 = new BNKPRD06(new iDB2Connection(ConfigurationManager.ConnectionStrings["DB2"].ConnectionString)); 
      Console.WriteLine(string.Format("{0}: Data contexts initialized", DateTime.Now.ToLongTimeString())); 

      var foo = from t in bank1.TMX9800F where t.T9ADDEP > 0 select t; // <- runs slow 
      Console.WriteLine(string.Format("{0}: {1} records found in BNKPRD01 test table", DateTime.Now.ToLongTimeString(), foo.Count().ToString())); 

      var baz = from t in bank6.TMX9800F where t.T9ADDEP > 0 select t; // <- runs slow 
      Console.WriteLine(string.Format("{0}: {1} records found in BNKPRD06 test table", DateTime.Now.ToLongTimeString(), baz.Count().ToString())); 

      var ds = new DataSet(); 
      using (var conn = new iDB2Connection(ConfigurationManager.ConnectionStrings["DB2"].ConnectionString)) 
      { 
       using (var cmd = conn.CreateCommand()) 
       { 
        cmd.CommandText = "SELECT * FROM BNKPRD01.TMX9800F WHERE T9ADDEP > 0"; 
        new IBM.Data.DB2.iSeries.iDB2DataAdapter(cmd).Fill(ds); 
       } 
      } 
      Console.WriteLine(string.Format("{0}: {1} records found in BNKPRD01 test table", DateTime.Now.ToLongTimeString(), ds.Tables[0].Rows.Count.ToString())); 

      ds = new DataSet(); 
      using (var conn = new iDB2Connection(ConfigurationManager.ConnectionStrings["DB2"].ConnectionString)) 
      { 
       using (var cmd = conn.CreateCommand()) 
       { 
        cmd.CommandText = "SELECT * FROM BNKPRD06.TMX9800F WHERE T9ADDEP > 0"; 
        new IBM.Data.DB2.iSeries.iDB2DataAdapter(cmd).Fill(ds); 
       } 
      } 
      Console.WriteLine(string.Format("{0}: {1} records found in BNKPRD06 test table", DateTime.Now.ToLongTimeString(), ds.Tables[0].Rows.Count.ToString())); 

      Console.WriteLine("Press return to exit."); 
      Console.ReadLine(); 
     } 

或者還有一些關於LINQ我沒有好感?

編輯

在與Jon及以下布萊恩,我再踏進創建和跨大步來到LINQ查詢時調用的代碼DB_Linq討論:

public override IEnumerable<MetaTable> GetTables() 
     { 
      const BindingFlags scope = BindingFlags.GetField | 
       BindingFlags.GetProperty | BindingFlags.Static | 
       BindingFlags.Instance | BindingFlags.NonPublic | 
       BindingFlags.Public; 
      var seen = new HashSet<Type>(); 
      foreach (var info in _ContextType.GetMembers(scope)) 
      { 
       // Only look for Fields & Properties. 
       if (info.MemberType != MemberTypes.Field && info.MemberType != MemberTypes.Property) 
        continue; 
       Type memberType = info.GetMemberType(); 

       if (memberType == null || !memberType.IsGenericType || 
         memberType.GetGenericTypeDefinition() != typeof(Table<>)) 
        continue; 
       var tableType = memberType.GetGenericArguments()[0]; 
       if (tableType.IsGenericParameter) 
        continue; 
       if (seen.Contains(tableType)) 
        continue; 
       seen.Add(tableType); 

       MetaTable metaTable; 
       if (_Tables.TryGetValue(tableType, out metaTable)) 
        yield return metaTable; 
       else 
        yield return AddTableType(tableType); 
      } 
     } 

那循環迭代16,718次。

+1

做BNKPRD ??類將所有表枚舉爲字段/屬性? – 2010-08-05 20:10:22

+0

@布萊恩:是的,他們有。 – David 2010-08-05 20:11:16

+0

@布萊恩:我認爲你在做點什麼。我剛剛在調試器中進一步介紹了DB_Linq代碼,並且遇到了一個方法,我將添加到問題中... – David 2010-08-05 20:22:06

回答

2

我剛剛在命名空間中創建了一個包含10.000個類的小型測試項目,並且在加載/裝配程序集時出現明顯的開銷,我不會說它特別慢。所以這可能不是類的數量本身,這是你看到糟糕表現的原因。

我是喬恩在這裏,這將有助於您的測試應用程序的更多信息。

+0

我認爲這是你上面的評論,在這一點上放大了比例,所以我會給你答案。在這一點上,我們已經超過了原來的問題(你和喬恩都有效地回答了這個問題),所以如果我在發展中遇到另一個潛在的障礙,我只會提出一個新的問題。謝謝! – David 2010-08-06 01:24:18

2

發佈控制檯應用程序真的很有幫助。

有一個命名空間和裝配體中的許多類會減慢編譯會有JITting對每類方法的一次打擊......但我不希望它慢下來LINQ查詢。

您應該檢查LINQ查詢中實際正在生成的SQL。我希望問題在於此。

+0

我也這麼認爲,但是如果我將代碼限制爲表的子集(比如說,其中的200個),那麼它會更快地運行_much_。我會看看我是否可以抓住生成的SQL並用它更新問題... – David 2010-08-05 19:37:00

+0

我只是想找一個地方發佈應用程序,當我意識到我會公開發布核心數據庫的整個結構時一家金融機構。我們可以整天辯論是否這是一個大問題,但最終這不是我們的呼籲:( – David 2010-08-05 19:56:29

+0

@大衛:啊,當你有一個表子集的速度提升點可能非常重要。仔細看看SQL,即使你不能發佈它 – 2010-08-05 20:04:38