ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: zhaogang1960

[讨论] SQL顺序连接多个工作簿速度的疑问,解释合理加技术分2分

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-3-11 14:00 | 显示全部楼层
没名字了 发表于 2014-3-11 13:53
我想今天能在这里讨论,恰恰是因为类似于连接这样的问题在显性声明和不声明上比较容易遇到,赵版可以换个思 ...

不能理解的是仅连接数据库,什么也不做速度会比有查询慢很多,应该不是声明的问题,估计是内存或你说的硬盘的速度的问题,当然我倾向于前者

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-3-11 14:03 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
HHAAMM 发表于 2014-3-11 13:55
看来只能这么解释
1、记录集对象在完成后有个关闭的动作
2、ado打开快于关闭

程序3:仅连接数据库,什么也不操作,速度比程序1有查询慢很多

记得循环连接前重新实例化连接对象即可,不用每次都关闭连接:
Set cnn = New ADODB.Connection

TA的精华主题

TA的得分主题

发表于 2014-3-11 14:11 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
第一段代码测试时间,添加 t
If MyName <> ThisWorkbook.Name Then
            t = Timer
            Set cnn = CreateObject("ADODB.Connection")
            cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=Excel 8.0;Data Source=" & Mypath & MyName
            SQL = "select * from [Sheet1$a2:l] where 被拆迁人 is not null"
            Set rs = cnn.Execute(SQL)
            arr = rs.GetRows
            Debug.Print Timer - t

.015625
0
.015625
0
0
.015625
0
.015625
0
0
.015625
0
0
.015625
0
.015625
0
0
.015625
0
0
.015625
0
.015625
0
0
.015625
0
0
.015625
0
0
.015625
0
.015625
0
0
.015625
0
0
.015625
0
0
.015625
0
.015625
0
0
.015625
0
0
.015625

第三段测试时间
.015625
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125
.046875
.03125

TA的精华主题

TA的得分主题

发表于 2014-3-11 14:11 | 显示全部楼层
我不是为了什么技术分来,我只是确实因为对这个话题比较感兴趣:
我的观点其实很简单,这两者的差异就是变量声明与否而采取的存储介质之间的速度的差异。
大家都知道变量是存储在内存里面。这个不用去证明。
excel 默认存储的方式,我猜测是采用文件存储的方式,也就是存储介质是硬盘,这从我前面说的几种保存方式以及贴的图片上或多或少可以证明一些。
加了set rs 就是以变量的方式去存储,也就是说利用内存去运作。
不加就是以系统默认方式去存储,可能就是以该文件自身的缓冲区去存储,实际上就是硬盘的存储与读取。
如果是这样,那么每次递增的时间应该基本上是恒定的。这也正好验证了我开始统计的速度差基本上是恒定的,set rs 的过程基本上速度不会变,而没有的可能会有细微的变化,那是由于如果文件在扇区内不是连续存储,就会造成一定的时间增加,但一般微乎其微,毕竟这个文件很小。
所以我个人认为这个和变量的声明有关,以及系统默认的存储介质(内存还是硬盘)有关。
仅个人观点,知识有限。不说了。

TA的精华主题

TA的得分主题

发表于 2014-3-11 14:14 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
第二段代码时间测试与第三段一直

这么说我50楼的答案是正确的

TA的精华主题

TA的得分主题

发表于 2014-3-11 14:33 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
zhaogang1960 发表于 2014-3-11 14:00
不能理解的是仅连接数据库,什么也不做速度会比有查询慢很多,应该不是声明的问题,估计是内存或你说的硬 ...

在三个过程的sql= 之前设断,三者时间是一致的。在我这里都是0.01625

TA的精华主题

TA的得分主题

发表于 2014-3-11 14:40 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
三个过程设断比较

过程3

过程3

过程2

过程2

过程1

过程1

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-3-11 14:51 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
HHAAMM 发表于 2014-3-11 14:14
第二段代码时间测试与第三段一直

这么说我50楼的答案是正确的

下面现象不好解释:
只要第一次连接使用Set rs=……,后面都不用速度更快
如果一次都不用,速度就慢

TA的精华主题

TA的得分主题

发表于 2014-3-11 14:56 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
zhaogang1960 发表于 2014-3-11 14:03
程序3:仅连接数据库,什么也不操作,速度比程序1有查询慢很多

记得循环连接前重新实例化连接对象即可 ...

创建并打开后什么都不做再次创建并打开,这么做其实也不会省去关闭的时间

我觉的原因就在Recordset对象上

TA的精华主题

TA的得分主题

发表于 2014-3-11 14:58 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 hehex 于 2014-3-11 15:32 编辑
zhaogang1960 发表于 2014-3-11 14:03
程序3:仅连接数据库,什么也不操作,速度比程序1有查询慢很多

记得循环连接前重新实例化连接对象即可 ...

综合了赵版和郝版以及上面几位网友的意见说说个人浅见:
修改了赵老师和郝版给的测试程序,用个一个52个元素的定长一维Double 数组来记录每次打开Connection 和生成游标的时间。其实就是把郝版的那个代码每次不debug.print 出来而是写到数组内。最后分别输出到一个新的工作表Sheet1 的3列内。

得到的测试数据发现,在未定义rs 变量时,就是第一次建立Connection 连接时,系统的时间是几乎相同的。
我们知道当ADO 对象建立Connect 连接时是要在堆内存(heap) 中开辟一片区域,用于存储当前连接数据表的数据,而且从理论上来说  
             Set rs = cnn.Execute(SQL)
             arr = rs.GetRows
应该占有系统时间及开销,但是从测试数据上几乎看不到分别,上一个帖子没名字网友的截图也说明了这一点。
那么就从现象上说明了一个问题:主要的时间开销来自ADO 对象Connection 操作,我们想想也是,连接数据表要有硬件IO,去硬盘上读取。

那么我们就主要认为是Connection 消耗了时间,其他操作暂时忽略掉时间的消耗。

然后从第2次循环就发生有意思的事情了:
没有指定rs 变量的再进行Connection 操作时速度变慢,慢出接近一倍,在我的机器上是0.04 秒接近到0.09 秒,然后每次进行Connection
基本都是这个速度。
而指定了rs 引用变量的程序呢,在Connection时速度不减反增,只用了没有指定的1/3 的时间。这是为什么呢?

在微软没有公开ADO 内存使用的详细解释之前,我只能做一下臆测:
首先rs 是什么? rs 是一个分配在Stack(栈区) 的引用变量,里面装的是RecordSet 这个实体数据集的引用。可能C,C++ 的开发者喜欢叫它指针,
总之通过rs 才可以访问到这个数据集。而RecordSet 是一个数据表的索引集,是根据SQL 语句生成的一个索引集。(这个我查了很久资料)是不能独立于
Connection 存在的,(这个我已经写程序测试过)那么我们可以认为,其实RecordSet 里面也只是一些索引,而得出的数据实体物理内存是装在Connection 里面的。
那么rs 就有点指针的指针的意思了。

那么RecordSet 对象存储在内存哪里呢?是堆内存(heap) 还是数据区开辟的缓存中呢?微软没有公布技术细节,我们无从得知。
我们仅仅从现象上知道的是开辟了RecordSet 的之后再打开Connection 速度会变快,否则变慢。

上面我说过了自己的观点,rs 变量是一个引用或者说是一个指针,只有通过这个保存的变量才能访问到RecordSet 实体,如果Conn.Execute(sql) 这么过去了,
返回值其实没有保留(被系统自动丢弃了),那么就是说虽然开辟了这个索引区域,而程序却无法访问到了,再下一次循环时该区域丢掉了(其实物理内存中还在,但是无法访问)。等于没开。

至于为什么开辟了RecordSet 连接其他数据表的Connection 方法速度就会变快,查了半天资料,去CSDN 问了半天,还是没得到确切的答案。只是从现象中看确实是这样,
是否是编译器,解释器优化的结果我们不清楚,也许是某些复杂的内存指针操作呢。微软一天不彻底公开所有细节,所有答案只能是猜测。

附件是我的测试程序,思想完全来自赵老师和郝版。





SQL顺序连接多个工作簿速度的疑问20072010.zip

36.09 KB, 下载次数: 25

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-19 01:29 , Processed in 0.036517 second(s), 8 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表