这是我问here问题的LINQ to DB2问题的下一步。
在zb_z的回答之后,我对DB_Linq的代码进行了一些讨论,并设法添加了有效的DB2支持。 (它现在还处于起步阶段,尚未准备好回馈到项目中。)概念验证工作得很好,实际上非常令人兴奋。但是,我一路上遇到了另一次打嗝。
事实证明,我们的DB2数据库大。 8,306桌大。因此,生成的代码竟然超过了520万行代码。在一个文件中。毋庸置疑,Visual Studio并不关心它:)
所以我进一步修改了生成器,将每个表类吐出到自己的文件中。这给我留下了8,307个文件(数据上下文和每个表一个,它们使用表属性扩展数据上下文)。 Visual Studio仍然不喜欢它,这是可以理解的,所以我将代码生成和编译包装在一个脚本中,然后运行它来为我的项目输出一个DLL。
一个36 MB的DLL。
现在,搜索一下性能导致我this SO question(它本身引用this one)并且我已经按照答案和链接查看他们在说什么。所以这让我想知道它是否可能在同一名称空间中存在超过8,000个类,这是明显的性能问题的罪魁祸首。
我的性能测试是编写一个初始化数据上下文的小型控制台应用程序,使用LINQ获取数据,打印行数,使用经典ADO获取数据,并打印出另一行计数。每个声明都包含一个时间戳。添加更多查询以进行测试等始终会产生相同的性能。 LINQ代码需要几秒钟才能运行,而ADO会在眨眼之间填充数据集。
所以我猜这最终会成为一个有点开放(并且啰嗦,抱歉)的问题。有没有人对加快绩效有任何想法?我可以应用哪些简单的调整或设计考虑因素?
修改
有几点需要注意:
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次。
答案 0 :(得分:2)
发布控制台应用程序确实会有所帮助。
在命名空间和程序集中有很多类会减慢编译,并且每种类型的每个方法都会有一次性的JITting命中...但我不会指望它可以减慢LINQ查询速度。
您应该检查从LINQ查询实际生成的SQL。我希望问题出在那里。
答案 1 :(得分:2)
我刚刚在命名空间中创建了一个带有10.000个类的小型测试项目,虽然在加载/ jitting组件时有明显的开销,但我不会说它特别慢。因此,可能不是类本身的数量,这是你所看到的糟糕表现的原因。
我是乔恩在这里,有关您的测试应用的更多信息会有所帮助。