这是我问的Linq to DB2问题的下一步
here
.
跟随
zb_z
答案是,我翻了一下密码
DB_Linq
并设法添加了有效的DB2支持。(现在它还处于初级阶段,还没有准备好为这个项目做出贡献。)概念验证非常有效,实际上非常令人兴奋。不过,我在路上碰到了另一个打嗝。
事实证明,我们的DB2数据库
大的
. 8306张大桌子。因此,生成的代码超过520万行。在一个文件中。不用说,Visual Studio不太关心它:)
所以我进一步修改了生成器,将每个表类吐出到自己的文件中。这给我留下了8307个文件(数据上下文和每个表一个,它用表属性扩展数据上下文)。Visual Studio仍然不喜欢它,这是可以理解的,所以我将代码生成和编译打包在一个脚本中,然后运行该脚本来输出一个供我的项目使用的DLL。
一个36兆字节的DLL。
现在,搜索一下性能,我发现
this SO question
(其本身引用
this one
)我跟踪了答案和链接,看看他们在说什么。因此,这让我想知道它是否可能在同一个名称空间中存在超过8000个类,而这正是引起显著性能问题的罪魁祸首。
我的性能测试是编写一个小控制台应用程序,它初始化数据上下文,用LINQ获取数据,打印行数,用经典ADO获取数据,并打印另一行数。每条语句都包含一个时间戳。向测试中添加更多的查询等总是产生相同的性能。LINQ代码运行需要几秒钟,而ADO则在眨眼间填充数据集。
所以我想这最终是一个有点开放性的问题(而且冗长的,对此感到抱歉)。有人对加速这里的表演有什么想法吗?有什么简单的调整,或者我可以应用的设计考虑吗?
编辑
需要注意的几点:
-
如果我将代码生成限制在表的一个子集(比如200)上,那么它将运行
许多的
更快。
-
在调试器中单步执行时,所花费的时间长度是
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();
}
也许我遗漏了一些明显的东西,或者我没有摸索过的林肯的某些东西?
编辑
在下面与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);
}
}
这个循环迭代16718次。