镜子里面的像为什么左右是反的而上下不是?
我问过很多朋友这个问题很少有人能够在3分钟内给出准确答案这里列举出一些比较奇特的想法
因为人的眼睛是左右对称的(也是某面试宝典中的答案)
如果把镜子横过来左右不反了上下却反了
因为我们在北半球
从技术层面上说这里涉及的知识点只有镜面反射远比Windows内存管理简单但是要回答清楚却不是信手拈来那么简单这个例子只是想说明除了知识以外解决问题需要清晰的思路
绝望的性能问题ADONET竟然比要慢
问题描述
根据下面一篇文章的介绍客户决定升级到NET Framework 来借助ADONET 提高性能
DataSet and DataTable in ADONET
但是根据用户的测试使用ADONET 后性能反而下降
拿到用户的代码一看非常简单
OracleConnection conn = new OracleConnection();
connConnectionString = ;
connOpen();
OracleCommand cmd = new OracleCommand();
cmdConnection = conn;
OracleDataAdapter dap = new OracleDataAdapter(select * from mytesttableconn);
DataTable dt = new DataTable();
DateTime start = SystemDateTimeNow;
dapFill(dt);
TimeSpan span = DateTimeNow start;
connClose();
ConsoleWriteLine(spanToString());
ConsoleWriteLine(The ColumnsCount is + dtColumnsCountToString());
ConsoleWriteLine(The RowsCount is+dtRowsCountToString());
测试用的数据库表也很简单万行数据个字段通过检查spanToString的结果发现同样的代码ADONET 比多用了近一倍的时间dapFill方法的执行时间从原来的秒增加到秒
悲观和绝望
应该如何着手解决这个问题?
我测试完成看到这个结果后我的感觉悲观看看我们能够做什么
后台数据库表格的定义非常简单个字段都是int都是在没有indexprimary keyforeign key等约束条件下测试的也就是说这个问题跟数据表的Schema定义无关完全是客户端的问题
代码已经非常简单Console工程里Main函数就做这么一件事情客户端没有任何可以修改和变动的地方
NET Framework 和NET Framework 共存在同一个客户端测试也是在同一个客户端进行的所以软硬件环境比如Oracle Client都相同唯一的区别就是NET Framework的版本这也就是客户最关心的地方
这个工具可以显示出每一个方法(包括子方法)调用所花费的时间以及占整体运行时间的比例为了让问题更加明显这里把数据库的行数增加了万来方便观察沿着花费时间比例最多的函数一路走下去发现DataReaderRead的方法实现分成两部分自身的托管代码调用和非托管代码调用分别占用了%左右的时间和%左右的时间有了这个信息后再通过Reflector分析ADONET中的对应函数的实现(VS自带的Profiler无法分析NET Framework 的程序不然直接分析两者时间比例就可以方便地看出问题)发现非托管代码部分的调用几乎没什么差别都是调入数据库的客户端非托管DLL主要差别在托管代码部分其中引起注意的是ADONET 增加了SafeHandleDangerous AddRef/DangerousRelease调用每一对这样的调用就要花费%的时间而每读取一行数据需要用大约对这样的调用经过比较分析认为问题就是在这里
由于对数据库的操作和数据填充最终通过调用非托管的数据库引擎来完成所以需要向非托管的DLL传入托管代码管理的缓存空间而SafeHandle就是管理这种资源的在NET Framework 中由于缺少SafeHandle类高负载环境下程序存在表现不稳定的危险没有完美的解决方法NET Framework 增加了SafeHandle来保证程序的可靠性然而代价就是万行数据发生秒钟的时间损失(后来经开发人员确认这秒钟的损失在下一版本的Framework也可以想办法优化掉!)
结论和收获
在跟客户作进一步的交流后这个问题的结论如下
MSDN文章的介绍是正确的如果用文章里面的例子的确可以看到性能有数量级上的提升
在客户的真实环境中损失的秒时间其实不会对最终用户和整个程序造成影响
秒钟不是白白损失的换来的是程序的可靠性