簡體   English   中英

性能問題 - 大型DLL和大型命名空間

[英]Performance Problems - Large DLLs and Large Namespaces

這是我在這里問到的LINQ to DB2問題的下一步。

zb_z的回答之后,我對DB_Linq的代碼進行了一些討論 ,並設法添加了有效的DB2支持。 (它現在還處於起步階段,尚未准備好回饋到項目中。)概念驗證工作得很好,實際上非常令人興奮。 但是,我一路上遇到了另一次打嗝。

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

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

一個36 MB的DLL。

現在,在性能上進行一些搜索使我得到了這個問題 (它本身就引用了這個 問題 ),我已經按照答案和鏈接看了他們在說什么。 因此,這讓我想知道它是否可能在同一名稱空間中存在超過8,000個類,這是明顯的性能問題的罪魁禍首。

我的性能測試是編寫一個初始化數據上下文的小控制台應用程序,使用LINQ獲取數據,打印行數,使用經典ADO獲取數據,並打印出另一行計數。 每個聲明都包含一個時間戳。 添加更多查詢以進行測試等始終會產生相同的性能。 LINQ代碼需要幾秒鍾才能運行,而ADO會在眨眼間填充數據集。

所以我想這最終會成為一個有點開放(並且啰嗦,抱歉)的問題。 有沒有人對加快績效有任何想法? 我可以應用哪些簡單的調整或設計考慮因素?

編輯

有幾點需要注意:

  1. 如果我將代碼生成限制為表的一個子集(例如,200),那么它運行更快。
  2. 在調試器中單步執行時,花費var foo = from t in bank1.TMX9800F where t.T9ADDEP > 0 select t.T9ADDEP上的var foo = from t in bank1.TMX9800F where t.T9ADDEP > 0 select t.T9ADDEP的行長度為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和Brian討論后,我進一步研究了在創建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次。

發布控制台應用程序真的會有所幫助。

在命名空間和程序集中有很多類會減慢編譯速度,每種類型的每個方法都會有一次性的JITting命中...但我不希望它會減慢LINQ查詢的速度。

您應該檢查從LINQ查詢實際生成的SQL。 我希望問題出在那里。

我剛剛在命名空間中創建了一個帶有10.000個類的小型測試項目,雖然在加載/ jitting組件時有明顯的開銷,但我不會說它特別慢。 因此,可能不是類本身的數量,這是你所看到的糟糕表現的原因。

我是喬恩在這里,它會對您的測試應用程序的更多信息有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM