VBA:在服务器上使用Excel查询Access

时间:2011-09-14 11:25:58

标签: performance ms-access vba

我正在使用Excel项目,这有助于计算任何家具和平的价格。第一项任务是从数据库中挑选所有材料。 这是代码:


Sub Material_search()
Dim cnt     As New ADODB.connection
Dim rst     As New ADODB.Recordset
Dim rcArray As Variant
Dim sSQL    As String
Dim db_path As String, db_conn As String
Dim item As String

item = Replace(TextBox1.Text, " ", "%")     ' Search word
sSQL = "Select Data, NomNr, Preke, Matas, Kaina, Tiek from VazPirkPrekes " & _
       "Where VazPirkPrekes.PirkVazID IN (SELECT VazPirkimo.PirkVazID FROM VazPirkimo Where VazPirkimo.Sandelys like '%ALIAVOS')" & _
       " and Year(VazPirkPrekes.Data)>=2011 and Preke Like '%" + item + "%' and Kaina > 0" & _
       " Order by Preke, Data Desc"
db_path = Sheets("TMP").Range("B6").value
db_conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & db_path & ";"
cnt.Open db_conn
rst.Open sSQL, cnt, adOpenForwardOnly, adLockReadOnly
ListBox1.Clear
If Not rst.EOF Then
    rcArray = (rst.GetRows)
    rcArray = WorksheetFunction.Transpose(rcArray)
    Dim a As Variant
    With ListBox1
        .ColumnCount = 6
        .list = rcArray
        .ListIndex = -1
    End With
End If
rst.Close: Set rst = Nothing
cnt.Close: Set cnt = Nothing
Label4.Caption = UBound(ListBox1.list) + 1
End Sub

最近我在查询Access mdb文件时遇到了一些麻烦。问题是当数据库文件在本地磁盘上时,搜索工作速度非常快,但是当我将数据库文件放在服务器上时,搜索需要花费10倍的时间,这是不可接受的。

这段代码有优化吗?或者是服务器问题

提前致谢

2 个答案:

答案 0 :(得分:1)

该查询要求Access'数据库引擎从两个表中检索所有190K行。毫不奇怪它很慢,当数据库引擎必须通过网络检索2 * 190K行时,速度会变慢。

如果TextBox1.Text包含“foo”,那么这就是您要求db引擎运行的语句:

Select Data, NomNr, Preke, Matas, Kaina, Tiek
from VazPirkPrekes
Where
    VazPirkPrekes.PirkVazID IN (
        SELECT VazPirkimo.PirkVazID
        FROM VazPirkimo
        Where VazPirkimo.Sandelys like '%ALIAVOS')
    and Year(VazPirkPrekes.Data)>=2011
    and Preke Like '%foo%'
    and Kaina > 0
Order by Preke, Data Desc

引擎必须从VazPirkimo表中检索所有190K行,然后才能确定哪些行包含以“ALIAVOS”结尾的Sandelys值。如果您的选择标准是“ALIAVOS”开头的值,则引擎可以使用Sandelys上的索引来限制它必须从VazPirkimo检索的行数。但是,由于该方法可能不适合您,因此请考虑将数字字段Sandelys_group添加到VazPirkimo并在Sandelys_group上创建索引。将Sandelys以“ALIAVOS”结尾的所有行设为相同的Sandelys_group编号(1)。然后你的“IN()”条件就是这样:

SELECT VazPirkimo.PirkVazID
FROM VazPirkimo
Where VazPirkimo.Sandelys_group = 1

Sandelys_group上的索引将允许db引擎仅检索匹配的行,这有望成为表中190K行的一小部分。

您可以进行其他更改以加快查询速度。从WHERE子句中查看此标准:

Year(VazPirkPrekes.Data)>=2011

这迫使数据库引擎从VazPirkPrekes中检索所有190K行,然后才能确定它们中的哪一行来自2011.使用Data的索引,这应该快得多:

VazPirkPrekes.Data >= #2011-01-01# AND VazPirkPrekes.Data < #2012-01-01#

使用Kaina上的索引时,此WHERE标准会更快:

Kaina > 0

您的ORDER BY请求Preke和Data上的索引。

Order by Preke, Data Desc

任何或所有这些更改都可以帮助加快查询,但我不知道多少。杀手就是这个WHERE标准:

Preke Like '%foo%'

这里的问题类似于“Sandelys like”比较的问题。由于这要求Preke包含“foo”的行,而不是以“foo”开头,因此db引擎无法利用Preke上的索引来仅检索匹配的行。它必须检索所有190K VazPirkPrekes行以确定哪个匹配。除非您可以为此使用不同的标准,否则您将受限于加快查询的速度。

答案 1 :(得分:0)

感谢您提供优化提示,但正如我所说,只有当我将数据库文件放在服务器上时才会出现问题。并且优化没有太大帮助。但我想到了其他的想法。

搜索空白“”会返回大约40k条记录(这些记录涵盖了我需要的所有内容)。因此,我将把所有这些记录放在workbook_activate事件的不同表单上,稍后只在该表中进行查询。

Sub Database_upload()
  Application.DisplayAlerts = False
  On Error Resume Next
  Sheets("DATA_BASE").Delete
  On Error GoTo 0
  Application.DisplayAlerts = False
  Sheets.Add
  ActiveSheet.name = "DATA_BASE"
  Sheets("DATA_BASE").Visible = False: Sheets("DARBALAUKIS").activate
  Dim cnt     As New ADODB.connection
  Dim rcArray As Variant
  Dim sSQL    As String
  Dim db_path As String, db_conn As String
  Dim item As String
  Dim qQt As QueryTable
  item = ""   'search for empty blanks  
  sSQL = "Select Data, NomNr, Preke, Matas, Kaina, Tiek from VazPirkPrekes " & _
         "Where VazPirkPrekes.PirkVazID IN (SELECT VazPirkimo.PirkVazID FROM VazPirkimo Where VazPirkimo.Sandelys like '%ALIAVOS')" & _
         " and Year(VazPirkPrekes.Data)>=2011 and Preke Like '%" + item + "%' and Kaina > 0" & _
         " Order by Preke, Data Desc"

  db_path = Sheets("TMP").Range("B6").value
  db_conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & db_path & ";"

  db_conn = "ODBC;DSN=MS Access 97 Database;"
  db_conn = db_conn & "DBQ=" & db_path
  Set qQt = Sheets("Sheet1").QueryTables.Add(connection:=db_conn, Destination:=Sheets("Sheet1").Range("A1"), Sql:=sSQL)
  qQt.Refresh BackgroundQuery:=False
End Sub

结果:

程序在启动时需要更长时间,但搜索时间是可以接受的 - 对我来说问题已经解决了:)