请教:实际应用DataTable和DataReader时的性能问题

时间:2022-02-27 18:18:01
程序的要求是这样的:数据库里存放了大量的商品信息(目前有5万多条,以后可能还会更多),在导入新的商品的时候,要自动判断这个待加入的商品在数据库中是否已经存在。其实就是对于每一条待加入商品,都要去扫描数据库里的每一条数据,基于字符串的比较来判定这两条数据是否重复或疑似重复(比较可能有多次,因为不是仅仅比较商品的名称,产地、品牌之类的属性也会进行比较)。 我尝试过的方案有两个:(1)使用DataTable一次性把大库的信息装载进来,并进行缓存,只要缓存不失效,除了第一次的查重操作,以后的查重操作都是在内存中进行的。(2)使用DataReader,每次查重操作都会返回一个新的SqlDataReader对象,然后用这个reader去遍历大库中的信息。

  目前在我的机器上,第二个方案的速度要略快于第一个(在已经有缓存的情况下,加入20条新的商品,第一个方案要54s,第二个方案要50s;但在没有缓存的情况下,第一个方案要先完成对DataTable的填充,需要近2分钟),所以看起来第二个方案略好。但我目前对两个方案都有很多疑惑:
(1)对第一种方案,像我这种使用web服务器缓存来试图提高效率的方法是不是不够通用,有没有什么更好的缓存方式或其他解决方法?
(2)DataReader怎么会比已经load到内存里的DataTable取数据的速度更快?还是它本来就确实很快?
(3)DataReader是不是对数据库服务器性能的依赖大于对Web服务器性能的依赖,而DataTable却正好相反?如果我在不更换DB服务器的前提下,提高Web服务器的性能配置,是不是第一种方案的效率有可能高于第二种方案?
(4)我们平常学到的算法分析,都是估算算法的复杂度。但对于这种实际的运行环境,往往涉及多个服务器,一次操作的时间不仅包含代码的运算时间,还包括数据的装载、传输的时间,对服务器的性能、网络带宽、缓存设置都有很大的相关性,如何在这样一个复杂的环境里把自己的代码性能调整到最好呢?

盼高手指教!

17 个解决方案

#1


datareader是只能向前滚动,且只读,所以速度上是比较快的

#2


DataReader更适用于你的要求,要是你有几十万条记录都用DataTable立马就死机了!

#3


建议DataReader

#4


谢各位。

另外不知大家对我的第4条疑问有何见解?

#5


另外,我们常说的“DataReader比DataTable快”,是不是加上了向DataTable里面load数据的时间?如果不考虑这个时间,只考虑从内存里的DataTable中遍历数据的时间,是不是依然要慢于DataReader?就我实际的测试,似乎慢的不多(54:50),而且似乎DataTable还有跟着服务器性能的提升而提升的空间。

#6


貌似依然是datareader快些

#7


然后用这个reader去遍历大库中的信息
——————————————————————————————————————————
不能这样用。你应该在查询SQL上写上条件,然后DBDataReader仅仅返回一条记录,而不是5万条。

#8


使用DBDataReader,每一个查询商品信息操作,应该不超过0.5秒钟(不明白你的50秒钟的测试有什么作用),并且并不需要任何预先对商品的查询,这才是该有的速度。

如果你的数据库引擎支持以 TableDirect 方式的DBCommand 来打开DBDatareader,然后使用主键直接定位记录,那么还可以加速200倍(我在两种数据库上测试过,最少快200倍)。这是在屋里内存完全富余的情况下。因此如果是web应用程序,那么本来可以服务几百个用户的服务器此时可能只能服务十几个用户了,要切记这个危险(因为通常开发人员不做压力测试,不关心负载问题)。

你可以将已经查询过的过的商品信息保存在一个 Dictionary<> 中,这样可以加速。

#9


我是没搞懂你要没一条都去比较干吗?直接SELECT COUNT(*) FROM tablename WHERE name = @Name不就行了么?让数据库去比较……

#10


在已经有缓存的情况下,加入20条新的商品,第一个方案要54s,第二个方案要50s
——————————————————————————————————————————
这个结果是怎么得来的?匪夷所思。单就功能来说,他们都不需要超过1秒钟就能完成。

但是如果你加入数据库或者Dictionary<>,由于已经索引了,所以查询很快。

学过数据库的人应该可以算得出来,遍历查询一个商品与按索引查询一个商品速度差2万多倍因此使用DataTable或者你所说的“遍历DataReader”我吓了一条,竟然还有不喜欢对5万条数据使用索引的。

#11


To Ivony:
判断一个商品是否重复不仅是看大库里有没有这个名字的字段,因为要考虑到原有的名字输入不规范和错别字的情况,所以整个判断算法是比较复杂的,利用到的字段也不仅是商品的名字,这个我在主贴里面也说过了。

To sp1234:
不知道你所说的“不需要超过1秒”是怎么得出的,正如我上面所说,由于判定的算法比较复杂,所以整个算法是在C#里实现的,而不是存储过程。对于每一条待加入的信息,如果这个信息以前大库中没有,那么我必须遍历完库中的每一条记录,对库里的每一条记录都和这个信息进行一定的判定算法之后,才能下结论。
当然,你说的利用索引来提高SqlDataReader读取数据的效率,非常感谢这个提醒 :)

#12


mark

#13


帮顶,学习

#14


MARK

#15


一个比较实用的方法,把产品名称or编号存入数据库的同时,也存一份到XML,读取XML的速度远快于数据库,而你要实现的只是查找xml是否有匹配的字段.\\
有=产品存在,提示. 
无=产品不存在,插入

#16


如果用存储过程可能速度会更快些.不会超过一秒的.

#17


to redeemleep:
不会吧,单就从xml中间load数据应该就不会快于数据库啊;况且,还要加上每次增加产品的时候去改写xml的开销。

to wdx1632:
我的处理过程里面,麻烦就麻烦在对两条记录做判定的算法比较复杂;不仅是要找出完全相同的记录,还要找出疑似相同的(比如“洛阳春都火腿”和“洛阳云都火腿”);而且基于的字段也远不止产品名字。其实最初的写法就是放到存储过程里的,结果比现在的方案慢了一倍左右。

#1


datareader是只能向前滚动,且只读,所以速度上是比较快的

#2


DataReader更适用于你的要求,要是你有几十万条记录都用DataTable立马就死机了!

#3


建议DataReader

#4


谢各位。

另外不知大家对我的第4条疑问有何见解?

#5


另外,我们常说的“DataReader比DataTable快”,是不是加上了向DataTable里面load数据的时间?如果不考虑这个时间,只考虑从内存里的DataTable中遍历数据的时间,是不是依然要慢于DataReader?就我实际的测试,似乎慢的不多(54:50),而且似乎DataTable还有跟着服务器性能的提升而提升的空间。

#6


貌似依然是datareader快些

#7


然后用这个reader去遍历大库中的信息
——————————————————————————————————————————
不能这样用。你应该在查询SQL上写上条件,然后DBDataReader仅仅返回一条记录,而不是5万条。

#8


使用DBDataReader,每一个查询商品信息操作,应该不超过0.5秒钟(不明白你的50秒钟的测试有什么作用),并且并不需要任何预先对商品的查询,这才是该有的速度。

如果你的数据库引擎支持以 TableDirect 方式的DBCommand 来打开DBDatareader,然后使用主键直接定位记录,那么还可以加速200倍(我在两种数据库上测试过,最少快200倍)。这是在屋里内存完全富余的情况下。因此如果是web应用程序,那么本来可以服务几百个用户的服务器此时可能只能服务十几个用户了,要切记这个危险(因为通常开发人员不做压力测试,不关心负载问题)。

你可以将已经查询过的过的商品信息保存在一个 Dictionary<> 中,这样可以加速。

#9


我是没搞懂你要没一条都去比较干吗?直接SELECT COUNT(*) FROM tablename WHERE name = @Name不就行了么?让数据库去比较……

#10


在已经有缓存的情况下,加入20条新的商品,第一个方案要54s,第二个方案要50s
——————————————————————————————————————————
这个结果是怎么得来的?匪夷所思。单就功能来说,他们都不需要超过1秒钟就能完成。

但是如果你加入数据库或者Dictionary<>,由于已经索引了,所以查询很快。

学过数据库的人应该可以算得出来,遍历查询一个商品与按索引查询一个商品速度差2万多倍因此使用DataTable或者你所说的“遍历DataReader”我吓了一条,竟然还有不喜欢对5万条数据使用索引的。

#11


To Ivony:
判断一个商品是否重复不仅是看大库里有没有这个名字的字段,因为要考虑到原有的名字输入不规范和错别字的情况,所以整个判断算法是比较复杂的,利用到的字段也不仅是商品的名字,这个我在主贴里面也说过了。

To sp1234:
不知道你所说的“不需要超过1秒”是怎么得出的,正如我上面所说,由于判定的算法比较复杂,所以整个算法是在C#里实现的,而不是存储过程。对于每一条待加入的信息,如果这个信息以前大库中没有,那么我必须遍历完库中的每一条记录,对库里的每一条记录都和这个信息进行一定的判定算法之后,才能下结论。
当然,你说的利用索引来提高SqlDataReader读取数据的效率,非常感谢这个提醒 :)

#12


mark

#13


帮顶,学习

#14


MARK

#15


一个比较实用的方法,把产品名称or编号存入数据库的同时,也存一份到XML,读取XML的速度远快于数据库,而你要实现的只是查找xml是否有匹配的字段.\\
有=产品存在,提示. 
无=产品不存在,插入

#16


如果用存储过程可能速度会更快些.不会超过一秒的.

#17


to redeemleep:
不会吧,单就从xml中间load数据应该就不会快于数据库啊;况且,还要加上每次增加产品的时候去改写xml的开销。

to wdx1632:
我的处理过程里面,麻烦就麻烦在对两条记录做判定的算法比较复杂;不仅是要找出完全相同的记录,还要找出疑似相同的(比如“洛阳春都火腿”和“洛阳云都火腿”);而且基于的字段也远不止产品名字。其实最初的写法就是放到存储过程里的,结果比现在的方案慢了一倍左右。