昨天写程序,有个小模块是通过分析数十万条记录,与异构的数据表进行比对,找出符合条件的信息。
在第一条查询中,需要查询所有记录的一个字段,并提取该字段中的第5至第10个字符串,要与异构数据表比较的就是这个字串。在最初的版本中,对于性能并没有做更多的考虑,先从数据表中获取所有的记录组成的数据集,作为目标数据,再从异构数据表中获取数据集作为比对数据,然后在程序中经过至少两次遍历,筛选出想要的结果。在这个版本中,效率很低。比对数据基本上固定,千把条的样子,目标数据很多,而且会越来越多。但性能的瓶颈并不是出现在程序中多次的遍历,这些都在内存中进行,这点数据量和算法,对于目前的服务器来说真的是小菜一碟。经测试,虽然只有几十万行的记录,查询时间却需要5秒以上。
我原来的思路是,因为担心SQL的性能,把从字段中截取字符串的计算由SQL移至程序中进行,但实践证明,对于返回大量记录的SQL,其效率反而更低了。于是,改变思路,还是利用SQL进行筛选,并尽量减少数据量,有了类似下面这一行简单的查询:
select distinct substring([prodcode],5,10) pcode from [detail] order by pcode
在这段查询中,首先是利用substring函数,在sql中就返回了要想的字符串,注意这里substring函数和C#中的区别,它是从1开始索引的,而C#中则是从0开始(我在此走了弯路,如果聪明的你早就知道,请忽略)。然后是前面有个关键字distinct,用来消除重复的记录(这里存在大量的重复值)。实践证明,虽然增加了一个截取字符串的计算,但由于返回的记录大大减少,这种情况下,数据库服务器返回结果的时间提升到0秒,也就是说已经是毫秒级了,SSMS(=查询分析器)给忽略了。
众所周知,I/O对程序性能的影响相当大,在这个小小的实例中也能看出这一点。最开始,我想当然的以为把计算移到程序中去做,减轻一下数据库的负担,同时提高运算效率,却忽略了这个问题。当SQL返回了大量数据,这些数据要从一个地方移动到另一个地方,从目前的网络性能来看,耽误的时间绝对是不可以忽略的。
这个故事告诉我们,不能想当然,做程序如此,做任何事情都是如此。
PS :最后不得不又要发个牢骚了,刚才提交的时候,差点又发生前功尽弃的事儿,正文文本框一片空白,和昨天提到的一样。也许是冥冥之中有神灵在帮我,在点提交按钮之前的那一瞬间,我打了个冷战,把这一堆文字复制到了记事本,不然现在可能已经变成了哭泣的百合。我估计的原因是,在文章发表页面花费的时间太长了。以前也给CSDN提过建议,增加一个自动保存到草稿箱的功能,但似乎没有反应。所以,还是自己以后多加个小心吧。