ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[求助] ADO+Access更新、插入速度优化

[复制链接]

TA的精华主题

TA的得分主题

发表于 2018-5-9 15:29 | 显示全部楼层 |阅读模式
Sub update()
'=======================================================================
'1、ID不为空表示数据库中已有对应数据,对这部分数据只更新字段值
'2、ID为空表示表格内新增的数据,直接上传数据到数据库
'=======================================================================
Dim con, rs, SQL$, i%, r%, c%
Dim insertRow As Integer '记录无ID的数据行(插入)
Dim updateRow As Integer '记录有ID的数据行(更新)
Dim updateSQL, insertSQL
If Range("A1").CurrentRegion.Rows.Count = 2 Then Exit Sub '如果工作表只有两行数据,退出、不执行
myPath = ThisWorkbook.Path & "\kanban.accdb"
myTable = "kanban"
If Range("A3") <> "" Then
r = Range("A" & Rows.Count).End(3).Row
For c = 2 To 18
updateSQL = updateSQL & "a.[" & Cells(2, c) & "]=b.[" & Cells(2, c) & "],"
Next
For c = 21 To 28
updateSQL = updateSQL & "a.[" & Cells(2, c) & "]=b.[" & Cells(2, c) & "],"
Next
updateSQL = VBA.Left(updateSQL, VBA.Len(updateSQL) - 1)
updateSQL = "update " & myTable & " a,[Excel 12.0;imex=0;Database=" & ActiveWorkbook.FullName & "].[看板汇总$A2:AB" & r & "] b set " & updateSQL & " where a.ID=b.ID"
End If
'1)引用ADO对象,以下是后期绑定的方式
Set con = CreateObject("adodb.connection") '建立ADO连接对象
Set rs = CreateObject("adodb.recordset") '建立ADO记录集对象

'3)建立连接
On Error GoTo errmsg
con.Open "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=" & myPath
con.Execute updateSQL
' MsgBox "数据已更新到数据库!", vbInformation, "更新数据"
con.Close
Set con = Nothing
Exit Sub
errmsg:
MsgBox Err.Description, , "错误报告"
End Sub

Sub AddNew()
Dim lR, uR '记录新增行行号
If Range("A1").CurrentRegion.Rows.Count = 2 Then Exit Sub
lR = Range("A" & Rows.Count).End(3).Row
uR = Range("B" & Rows.Count).End(3).Row
If uR < 3 Then Exit Sub
r = Sheets("看板汇总").Range("B" & Rows.Count).End(3).Row
myPath = ThisWorkbook.Path & "\kanban.accdb"
myTable = "kanban"
'构造SQL
For c = 2 To 18
insertSQL = insertSQL & "[" & Cells(2, c) & "],"
Next
For c = 21 To 28
insertSQL = insertSQL & "[" & Cells(2, c) & "],"
Next
insertSQL = VBA.Left(insertSQL, VBA.Len(insertSQL) - 1)
insertSQL = "insert into " & myTable & " select " & insertSQL & " from [Excel 12.0;Database=" & ActiveWorkbook.FullName & "].[看板汇总$A2:AB" & r & "] where ID is null"
Debug.Print insertSQL
'1)引用ADO对象,以下是后期绑定的方式
Set con = CreateObject("adodb.connection") '建立ADO连接对象
Set rs = CreateObject("adodb.recordset") '建立ADO记录集对象
'3)建立连接
On Error GoTo errmsg
con.Open "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=" & myPath
con.Execute insertSQL
' MsgBox "数据已添加到数据库!", vbInformation, "添加数据"
con.Close
Set con = Nothing
Exit Sub
errmsg:
MsgBox Err.Description, , "错误报告"
End Sub

以上两段代码:
过程 update 向数据库更新 看板汇总 中有ID的数据
过程 AddNew 向数据库插入 看板汇总 中ID为空的数据

问题:
看板汇总中数据比较少时速度挺快的,但是数据达到1万行左右时速度就特别慢,会导致Excel假死,哪位老师有办法帮我优化一下?

HELPME.rar

216.5 KB, 下载次数: 32

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-5-9 15:41 | 显示全部楼层
  1. Sub update()
  2. '=======================================================================
  3. '1、ID不为空表示数据库中已有对应数据,对这部分数据只更新字段值
  4. '2、ID为空表示表格内新增的数据,直接上传数据到数据库
  5. '=======================================================================
  6. Dim con, rs, SQL$, i%, r%, c%
  7. Dim insertRow As Integer '记录无ID的数据行(插入)
  8. Dim updateRow As Integer '记录有ID的数据行(更新)
  9. Dim updateSQL, insertSQL
  10. If Range("A1").CurrentRegion.Rows.Count = 2 Then Exit Sub '如果工作表只有两行数据,退出、不执行
  11. myPath = ThisWorkbook.Path & "\kanban.accdb"
  12. myTable = "kanban"
  13. If Range("A3") <> "" Then
  14. r = Range("A" & Rows.Count).End(3).Row
  15. For c = 2 To 18
  16. updateSQL = updateSQL & "a.[" & Cells(2, c) & "]=b.[" & Cells(2, c) & "],"
  17. Next
  18. For c = 21 To 28
  19. updateSQL = updateSQL & "a.[" & Cells(2, c) & "]=b.[" & Cells(2, c) & "],"
  20. Next
  21. updateSQL = VBA.Left(updateSQL, VBA.Len(updateSQL) - 1)
  22. updateSQL = "update " & myTable & " a,[Excel 12.0;imex=0;Database=" & ActiveWorkbook.FullName & "].[看板汇总$A2:AB" & r & "] b set " & updateSQL & " where a.ID=b.ID"
  23. End If
  24. '1)引用ADO对象,以下是后期绑定的方式
  25. Set con = CreateObject("adodb.connection") '建立ADO连接对象
  26. Set rs = CreateObject("adodb.recordset") '建立ADO记录集对象

  27. '3)建立连接
  28. On Error GoTo errmsg
  29. con.Open "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=" & myPath
  30. con.Execute updateSQL
  31. ' MsgBox "数据已更新到数据库!", vbInformation, "更新数据"
  32. con.Close
  33. Set con = Nothing
  34. Exit Sub
  35. errmsg:
  36. MsgBox Err.Description, , "错误报告"
  37. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-5-9 15:41 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
  1. Sub AddNew()
  2. Dim lR, uR '记录新增行行号
  3. If Range("A1").CurrentRegion.Rows.Count = 2 Then Exit Sub
  4. lR = Range("A" & Rows.Count).End(3).Row
  5. uR = Range("B" & Rows.Count).End(3).Row
  6. If uR < 3 Then Exit Sub
  7. r = Sheets("看板汇总").Range("B" & Rows.Count).End(3).Row
  8. myPath = ThisWorkbook.Path & "\kanban.accdb"
  9. myTable = "kanban"
  10. '构造SQL
  11. For c = 2 To 18
  12. insertSQL = insertSQL & "[" & Cells(2, c) & "],"
  13. Next
  14. For c = 21 To 28
  15. insertSQL = insertSQL & "[" & Cells(2, c) & "],"
  16. Next
  17. insertSQL = VBA.Left(insertSQL, VBA.Len(insertSQL) - 1)
  18. insertSQL = "insert into " & myTable & " select " & insertSQL & " from [Excel 12.0;Database=" & ActiveWorkbook.FullName & "].[看板汇总$A2:AB" & r & "] where ID is null"
  19. Debug.Print insertSQL
  20. '1)引用ADO对象,以下是后期绑定的方式
  21. Set con = CreateObject("adodb.connection") '建立ADO连接对象
  22. Set rs = CreateObject("adodb.recordset") '建立ADO记录集对象
  23. '3)建立连接
  24. On Error GoTo errmsg
  25. con.Open "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=" & myPath
  26. con.Execute insertSQL
  27. ' MsgBox "数据已添加到数据库!", vbInformation, "添加数据"
  28. con.Close
  29. Set con = Nothing
  30. Exit Sub
  31. errmsg:
  32. MsgBox Err.Description, , "错误报告"
  33. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-5-9 19:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
经测试是过程 update 中的 update语句执行慢
  1. update kanban a,[Excel 12.0;imex=0;Database=C:\Users\Administrator\Desktop\看板系统开发\看板汇总.xlsm].[看板汇总$A2:AB35296] b set a.[生产任务号]=b.[生产任务号],a.[整机代码]=b.[整机代码],a.[规格型号]=b.[规格型号],a.[数量]=b.[数量],a.[销售员]=b.[销售员],a.[出货日期/总装完成日期]=b.[出货日期/总装完成日期],a.[PMC调整后原出货日期]=b.[PMC调整后原出货日期],a.[下达车间日期]=b.[下达车间日期],a.[原计划配料时间]=b.[原计划配料时间],a.[PMC调整总装配料日期]=b.[PMC调整总装配料日期],a.[总装物料到料日期]=b.[总装物料到料日期],a.[总装仓库实际配料日期]=b.[总装仓库实际配料日期],a.[仓库总装配料异常]=b.[仓库总装配料异常],a.[总装车间投入时间]=b.[总装车间投入时间],a.[总装完成数量]=b.[总装完成数量],a.[总装完成时间]=b.[总装完成时间],a.[总装异常]=b.[总装异常],a.[计划部相关备注说明]=b.[计划部相关备注说明],a.[责任部门]=b.[责任部门],a.[插单]=b.[插单],a.[提前订单]=b.[提前订单],a.[任务书登记日期]=b.[任务书登记日期],a.[电机类别]=b.[电机类别],a.[排产计划]=b.[排产计划],a.[销售发货计划日期]=b.[销售发货计划日期] where a.ID=b.ID
复制代码

单独执行过程AddNew还是很快的,不知道这个update语句还能优化吗

TA的精华主题

TA的得分主题

发表于 2018-5-9 20:22 来自手机 | 显示全部楼层
imex=0我记得是汇入,汇出可能是 imex=1;汇总$A2:AB35296,每次都要更新这么多行列的数据吗?

TA的精华主题

TA的得分主题

发表于 2018-5-9 20:39 | 显示全部楼层

你的数据库至少要版本14.0,我的2007没法玩。看了一下代码,建议你:

在update中去掉Set con = Nothing,并把con定义为公共变量,这样每次更新时,无需从头新建连接。

建立连接通信需要消耗很多资源,会影响速度。每次update完成,只需close,下车调用open就行了。

可以用con.state=adStateOpen看是不是断开,如果关闭,open之。

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-5-9 21:35 | 显示全部楼层
ivccav 发表于 2018-5-9 20:39
你的数据库至少要版本14.0,我的2007没法玩。看了一下代码,建议你:

在update中去掉Set con = Nothin ...

谢谢,不过我的表格是要分发给多人使用的,这样做会不会有影响?

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-5-9 21:38 | 显示全部楼层
zpy2 发表于 2018-5-9 20:22
imex=0我记得是汇入,汇出可能是 imex=1;汇总$A2:AB35296,每次都要更新这么多行列的数据吗?

目前已经有1万行数据,大概每年能增加1万行

TA的精华主题

TA的得分主题

发表于 2018-5-9 21:47 | 显示全部楼层
本帖最后由 ivccav 于 2018-5-9 21:48 编辑
zhongchangliang 发表于 2018-5-9 21:35
谢谢,不过我的表格是要分发给多人使用的,这样做会不会有影响?


不会有影响。你的表格相当于客户端,每个客户端都可以连接数据库。每次使用完都应该断开,再用时再打开。

你的更新和添加都应该使用公共连接对象。大致的代码如下,仅供参考:

  1. Public conn As ADODB.Connection

  2. Sub pubconn()
  3.     Dim strConnStr As String
  4.     strConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=d:\myFolder\myAccessFile.accdb;"
  5.     Set conn = New ADODB.Connection
  6.     conn.Open
  7.     conn.Close
  8. End Sub

  9. Sub test()
  10. If conn Is Nothing Then Call pubconn
  11. If Not conn.State = adStateOpen Then conn.Open
  12. '......
  13. conn.Close
  14. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2018-5-9 22:32 | 显示全部楼层
where ID is null 非常耗费资源。建议 ID 值默认为0 where ID =0 。
update 不要直接使用单元格,全表存入数组,用循环方式逐条更新。
字段值预先判定格式 isnumeric(),isdate(),len()>0空值直接跳过,set 字段名=字段值
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-9-29 10:27 , Processed in 0.034673 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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