ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 38536|回复: 148

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

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2014-3-10 19:10 | 显示全部楼层 |阅读模式
本帖最后由 zhaogang1960 于 2014-3-10 23:41 编辑

在解决使用SQL合并多个工作簿数据时发现:采用顺序连接每个工作簿,用GetRows方法把查询数据写入数组,采用下面两种方式速度上有很大差异,如果不加类似Set rs = cnn.Execute(SQL)语句,即使仅保留连接数据库语句,其他什么也不做,速度也会变得很慢,见第3种情况,原题目见下面链接:
跨工作簿汇总

1
Set rs = cnn.Execute(SQL)
arr = rs.GetRows
  1. Sub ADO加数组已知工作表名_1() '使用Set rs = cnn.Execute(SQL),arr = rs.GetRows
  2. tt = Timer
  3.     Dim cnn As Object, rs As Object, SQL$, Mypath$, MyName$, arr, brr(1 To 60000, -1 To 11), i&, j&, m&, n&
  4.     Application.ScreenUpdating = False
  5.     Mypath = ThisWorkbook.Path & ""
  6.     MyName = Dir(Mypath & "*.xls")
  7.     Do While MyName <> ""
  8.         If MyName <> ThisWorkbook.Name Then
  9.             Set cnn = CreateObject("ADODB.Connection")
  10.             cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=Excel 8.0;Data Source=" & Mypath & MyName
  11.             SQL = "select * from [Sheet1$a2:l] where 被拆迁人 is not null"
  12.             Set rs = cnn.Execute(SQL)
  13.             arr = rs.GetRows
  14.             For i = 0 To UBound(arr, 2)
  15.                 m = m + 1
  16.                 brr(m, -1) = m
  17.                 For j = 0 To 11
  18.                     brr(m, j) = arr(j, i)
  19.                 Next
  20.             Next
  21.         End If
  22.         MyName = Dir()
  23.     Loop
  24.     [a1].CurrentRegion.Offset(2).ClearContents
  25.     [a3].Resize(m, 13) = brr
  26.     rs.Close
  27.     cnn.Close
  28.     Set rs = Nothing
  29.     Set cnn = Nothing
  30.     MsgBox Timer - tt
  31. End Sub
复制代码
2、
arr = cnn.Execute(SQL).GetRows
  1. Sub ADO加数组已知工作表名_2() 'arr = cnn.Execute(SQL).GetRows
  2. tt = Timer
  3.     Dim cnn As Object, SQL$, Mypath$, MyName$, arr, brr(1 To 60000, -1 To 11), i&, j&, m&, n&
  4.     Application.ScreenUpdating = False
  5.     Mypath = ThisWorkbook.Path & ""
  6.     MyName = Dir(Mypath & "*.xls")
  7.     Do While MyName <> ""
  8.         If MyName <> ThisWorkbook.Name Then
  9.             Set cnn = CreateObject("ADODB.Connection")
  10.             cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=Excel 8.0;Data Source=" & Mypath & MyName
  11.             SQL = "select * from [Sheet1$a2:l] where 被拆迁人 is not null"
  12.             arr = cnn.Execute(SQL).GetRows
  13.             For i = 0 To UBound(arr, 2)
  14.                 m = m + 1
  15.                 brr(m, -1) = m
  16.                 For j = 0 To 11
  17.                     brr(m, j) = arr(j, i)
  18.                 Next
  19.             Next
  20.         End If
  21.         MyName = Dir()
  22.     Loop
  23.     [a1].CurrentRegion.Offset(2).ClearContents
  24.     [a3].Resize(m, 13) = brr
  25.     cnn.Close
  26.     Set cnn = Nothing
  27.     MsgBox Timer - tt
  28. End Sub
复制代码
3、第一种情况速度很快,第二种情况后者速度很慢,甚至仅保留连接工作簿语句,删除查询语句时,速度也很慢的奇怪现象:
  1. Sub ADO加数组已知工作表名_3() '仅连接工作簿,不做任何操作
  2. tt = Timer
  3.     Dim cnn As Object, SQL$, Mypath$, MyName$, arr, brr(1 To 60000, -1 To 11), i&, j&, m&, n&
  4.     Application.ScreenUpdating = False
  5.     Mypath = ThisWorkbook.Path & ""
  6.     MyName = Dir(Mypath & "*.xls")
  7.     Do While MyName <> ""
  8.         If MyName <> ThisWorkbook.Name Then
  9.             Set cnn = CreateObject("ADODB.Connection")
  10.             cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=Excel 8.0;Data Source=" & Mypath & MyName
  11.             SQL = "select * from [Sheet1$a2:l] where 被拆迁人 is not null"
  12. '            arr = cnn.Execute(SQL).GetRows
  13. '            For i = 0 To UBound(arr, 2)
  14. '                m = m + 1
  15. '                brr(m, -1) = m
  16. '                For j = 0 To 11
  17. '                    brr(m, j) = arr(j, i)
  18. '                Next
  19. '            Next
  20.         End If
  21.         MyName = Dir()
  22.     Loop
  23. '    [a1].CurrentRegion.Offset(2).ClearContents
  24. '    [a3].Resize(m, 13) = brr
  25.     cnn.Close
  26.     Set cnn = Nothing
  27.     MsgBox Timer - tt
  28. End Sub
复制代码

请看附件
SQL顺序连接多个工作簿速度的疑问.rar (305.58 KB, 下载次数: 210)

Excel2007或2010附件:
SQL顺序连接多个工作簿速度的疑问20072010.rar (443.85 KB, 下载次数: 224)
该贴已经同步到 zhaogang1960的微博

TA的精华主题

TA的得分主题

发表于 2014-3-10 21:09 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
很怪异,BUG?

TA的精华主题

TA的得分主题

发表于 2014-3-10 23:15 | 显示全部楼层
多处放置time做了测试 发现关键在这里
           Set rs = cnn.Execute(SQL)'1里注释掉这句就会一样速度了
2方法中没有显示创建rs,系统总是会隐式创建rs对象,看测试的结果就是隐式创建的速度很慢,当我把1中set rs这句注释掉 速度就和2一样了 所以我觉得bug应该就是这个了

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-3-10 23:22 | 显示全部楼层
本帖最后由 zhaogang1960 于 2014-3-10 23:25 编辑
百度不到去谷歌 发表于 2014-3-10 23:15
多处放置time做了测试 发现关键在这里
           Set rs = cnn.Execute(SQL)'1里注释掉这句就会一样速度了 ...

谢谢回复,我也是这样想的:
只要连接数据库,就会自动产生一个rs对象,不管该对象本质是什么,都要赋给一个对象变量rs,如Set rs = cnn.OpenSchema(adSchemaTables)取得工作表名、Set rs =cnn.Execute(SQL)查询等,否则如果继续连接下一个数据库,又会产生一个rs对象,会连续占用内存,从而导致速度变慢。
但没有理论根据啊

TA的精华主题

TA的得分主题

 楼主| 发表于 2014-3-11 00:05 | 显示全部楼层
liucqa 发表于 2014-3-10 23:41
加上这个看看  

cnn.CursorLocation = adUseClient

谢谢回复,经测试:
第一、cnn.CursorLocation = adUseClient没有任何影响
cnn.Open "Provider=Microsoft.ace.OLEDB.12.0;Extended Properties=Excel 12.0;Data Source=" & myPath & MyName
改为
            With cnn
                .Provider = "Microsoft.Ace.OLEDB.12.0"
                .ConnectionString = "Data Source=" & myPath & MyName & ";Extended Properties=Excel 12.0"
                .CursorLocation = adUseClient
                .Open
            End With

第二、  
Set rs = cnn.Execute(SQL)
arr = rs.GetRows

rs.Open SQL, cnn, adOpenKeyset, adLockOptimistic'1,3
arr = rs.GetRows
速度一样,都很快

TA的精华主题

TA的得分主题

发表于 2014-3-11 07:07 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2014-3-11 08:59 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
个人感觉没有依据也仅仅是猜测:
excel打开的时候是会在系统temp里面增加两个缓存文件,word则是在当前目录根据修改次数创建多个。(关闭时自动删除)
所以有这样的猜测,但未必准确
当我们预设了RS的时候,读取内容的存储是利用硬件内存空间。没有预设的时候,它会找一个缓存查询数据的硬盘物理空间去存储,以防大量消耗内存造成系统崩溃。这个时间差异可能就是由此产生。但是我刚才跟踪了一下它的缓存文件,发现大小并没有改变。也可能说明我的想法是错的。
不过我又实验了一下文件数量的影响,当我们只用一个数据源表的时候,速度基本上完全是一致。这又让我觉得这其中一定涉及到一个写入和清除的过程时间。

TA的精华主题

TA的得分主题

发表于 2014-3-11 09:26 | 显示全部楼层
本帖最后由 百度不到去谷歌 于 2014-3-11 09:32 编辑
没名字了 发表于 2014-3-11 08:59
个人感觉没有依据也仅仅是猜测:
excel打开的时候是会在系统temp里面增加两个缓存文件,word则是在当前目录 ...

我觉得可能是隐式创建的rs会预分配比较大的内存空间导致速度变慢,而执行sql语句显式赋值的rs有确定的结果集,其空间占用反而小一些又或者是隐式创建的机制本身就慢一些  不能知ado的内部原理 只能猜测了

TA的精华主题

TA的得分主题

发表于 2014-3-11 09:38 | 显示全部楼层
百度不到去谷歌 发表于 2014-3-11 09:26
我觉得可能是隐式创建的rs会预分配比较大的内存空间导致速度变慢,而执行sql语句显式赋值的rs有确定的结果 ...

也有这个可能,而且比我的猜测更靠谱些:以下是我的测试,很有规律的
文件数量        时间1        时间2        时间1上下差|时间2上下差|两时间差
1        0.046875        0.046875                       
2        0.0625        0.09375        0.015625        0.046875        0.03125
3        0.078125        0.140625        0.015625        0.046875        0.03125
4        0.09375        0.171875        0.015625        0.03125        0.015625
5        0.078125        0.21875        -0.015625        0.046875        0.0625
6        0.09375        0.25        0.015625        0.03125        0.015625
7        0.109375        0.28125        0.015625        0.03125        0.015625
8        0.125        0.328125        0.015625        0.046875        0.03125

TA的精华主题

TA的得分主题

发表于 2014-3-11 09:52 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
重新测试了一下 想起rs对象 在1中声明他以后 在循环中每次都是赋值给他新的sql结果  这样每次rs都没有关闭,也就是说使用的是同一个rs对象 ,只是每次接收不同的结果
而2隐式创建rs的话 每次执行sql的时候,实际上都需要重新创建一个rs对象 这就是为什么只执行一次的话,效率差不多
我在1代码中   loop前加上这个语句 速度就明显变慢了
Set rs = Nothing
    Loop
应该就是2中每次rs都需要重新创建耗费了时间!
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-5-2 12:42 , Processed in 0.043542 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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