2009-10-15 2 views
3

Я нашел этот код в Интернете, чтобы запросить доступ и ввод данных в Excel (2003), но гораздо медленнее, чем это должно быть:VBA: запрос доступа с помощью Excel. Почему так медленно?

Sub DataPull(SQLQuery, CellPaste) 
Dim Con As New ADODB.Connection 
Dim RST As New ADODB.Recordset 
Dim DBlocation As String, DBName As String 
Dim ContractingQuery As String 

If SQLQuery = "" Then 

Else 
    DBName = Range("DBName") 
    If Right(DBName, 4) <> ".mdb" Then DBName = DBName + ".mdb" 

    DBlocation = ActiveWorkbook.Path 
    If Right(DBlocation, 1) <> "\" Then DBlocation = DBlocation + "\" 

    Con.ConnectionString = DBlocation + DBName 
    Con.Provider = "Microsoft.Jet.OLEDB.4.0" 
    Con.Open 

    Set RST = Con.Execute(SQLQuery) 
    Range(CellPaste).CopyFromRecordset RST 

    Con.Close 
End If 

End Sub 

Проблема заключается в том, что этот код занимает очень много времени. Если я открою Access и просто запустил запрос, он займет около 1/10 времени. Есть ли способ ускорить это? Или по какой-либо причине это может занять так много времени? Все мои запросы - это простые запросы выбора с простыми инструкциями и объединениями. Даже запрос «select * from [test]» занимает гораздо больше времени, чем нужно.

EDIT: Я должен указать, что линия «Range (CellPaste) .CopyFromRecordset RST» была длительной.

+1

При запуске в режиме перехода по экрану, какая строка кода занимает больше времени? – shahkalpesh

+0

Диапазон (CellPaste) .CopyFromRecordset RST – Dan

+0

Сколько записей вы извлекаете? – Thorsten

ответ

1

Многие формулы могут ссылаться на запрос. Попробуйте временно включить ручной расчет в макросе и отключите его, когда все ваши запросы будут обновлены.

Это должно ускорить его, но по-прежнему не устраняет основную проблему.

3

Я не эксперт, но я выполняю почти точно такой же код с хорошими результатами. Одно отличие состоит в том, что я использую объект Command, а также объект Connection. Где вы

Set RST = Con.Execute(SQLQuery) 

Я

Dim cmd As ADODB.Command 
Set cmd.ActiveConnection = con 
cmd.CommandText = SQLQuery 
Set RST = cmd.Execute 

Я не знаю, или почему это может помочь, но, возможно, это будет? :-)

1

Я бы рекомендовал вам создать Recordset явно, а не неявно, используя метод Execute. При создании явно вы можете установить свойства CursorType и LockType, которые влияют на производительность.

Из того, что я вижу, вы загружаете данные в Excel, а затем закрываете набор записей. Вам не нужно обновлять, подсчитать количество записей, и т.д ... Так что мой совет должен был бы создать Recordset с CursorType = adOpenForwardOnly & LockType = adLockReadOnly:

... 
RST.Open SQLQuery, Con, adOpenForwardOnly, adLockReadOnly 
Range(CellPaste).CopyFromRecordset RST 
... 

Recordset Object (ADO)

+0

Я попробовал. Это сработало, но не привело к разнице во времени выполнения. Спасибо, в любом случае. – Dan

1

Поскольку вы используете Access 2003, использовать DAO вместо , он будет быстрее с двигателем Jet.

См. http://www.erlandsendata.no/english/index.php?d=envbadacexportdao для примера кода.

Обратите внимание, что никогда не следует использовать ключевое слово «Как новое», так как это приведет к неожиданным результатам.

+0

Это проблематично, потому что не у всех есть DAO, поэтому это затруднит передачу этого файла другим людям. – Dan

+1

То же самое можно было бы применить к ADO. Я понимаю, что DAO является частью или тесно связана с движком Jet, используемым Access 2003. Поэтому маловероятно, что он не будет присутствовать вместе с Access. Но вы всегда можете проверить следующее место для него: C: \ Program Files \ Common Files \ Microsoft Shared \ DAO \ dao360.dll (предполагается, что DAO 3.6) Кроме того, необходимо будет преобразовать код в конце границы , и используйте только код DAO, если файл присутствует. – JimmyPena

+0

Он также присутствует в Excel, поскольку движок Jet db является компонентом Office, а Excel довольно тесно интегрирован с ним. –

0

Если вы получаете много записей, это объясняет, почему Range(CellPaste) занимает так много времени. (При выполнении запроса в Access не будет извлекать все записи, но если вы делаете CopyFromRecordset это требует все записи.)

Существует параметр MaxRows для CopyFromRecordset:

Public Function CopyFromRecordset (_ 
    Data As Object, _ 
    <OptionalAttribute> MaxRows As Object, _ 
    <OptionalAttribute> MaxColumns As Object _ 
) As Integer 

Try если настройки с низким значением (например, 10 или около того) изменят производительность.

0

насчет следующих ремонтов или улучшений:

  1. После открытия, сохранения записей в виде XML-файла (rst.saveToFile ххх), а затем уже Excel открыть его.
  2. После открытия поместите данные набора записей в массив (сначала.getRows xxx) и скопируйте массив на активном листе
  3. И в любое время свести к минимуму все требования к памяти/доступу: откройте набор записей только для чтения, только вперед, закройте соединение, как только данные будут на вашей стороне, и т. д.
1

Я использовал ваш код и потянул за стол из 38 столбцов и 63780 строк менее чем за 7 секунд - о том, чего я ожидал, - и небольшие наборы записей были выполнены почти мгновенно.

Является ли это видом производительности, который вы испытываете? Если это так, это согласуется с тем, что я ожидаю при подключении ADO из Excel к серверу MDB.

Если вы видите гораздо более медленную производительность, чем это, тогда должны быть некоторые локальные условия среды, которые влияют на вещи.

1

Я не думаю, что вы сравниваете подобное с подобным.

В Access при просмотре DataView запроса, то, что происходит, является:

  • существующего открытого соединения используется (и остается открытым);
  • набор записей частично заполнен только с первыми несколькими строками (и открыт);
  • частичные набор результаты показаны в сетки, посвященной задачу и оптимизированной для нативного доступа к данным метода доступа использует (прямое использование доступа к базе данных библиотек DLL Engine, вероятно).

В коде VBA:

  • открывается новое соединение (то позже закрыто и освобожден);
  • набор записей полностью заполнен с использованием всех строк (затем позже закрыт и выпущен );
  • весь набор результатов считывается в общий пользовательский интерфейс Excel с использованием не входящих в состав данных компонентов доступа к данным.

Я думаю, что самый важный момент в том, что dataview в Access не извлекает весь набор результатов, пока вы его не попросите, как правило, путем перехода к последней строке в наборе результатов. ADO всегда будет извлекать все строки в наборе результатов.

Вторым наиболее важным было бы время, затраченное на считывание извлеченных строк (при условии полного набора результатов) в элемент пользовательского интерфейса и тот факт, что Excel не оптимизирован для задания.

Открывающие, закрывающие и освобождающие соединения и наборы записей должны быть несущественными, но все же фактором.

Я думаю, вам нужно сделать некоторые тайминги на каждом этапе процесса, чтобы найти узкое место. По сравнению с Access, убедитесь, что вы получаете полный набор результатов, например. проверьте количество возвращенных строк.

0

Я не знаю, поможет ли это, но я использую VBA и ADO для подключения к электронной таблице Excel.

Он извлекал записи молниеносно (< 5 секунд), но потом внезапно это было ужасно медленно (15 секунд, чтобы получить одну запись). Это то, что привело меня к вашему посту.

Я понял, что я случайно открыл файл Excel (я его редактировал).

Как только я закрыл его, все снова засияло.

0

Проблема 9 раз из 10 связана с типом/местоположением курсора, который вы используете.

Использование динамических курсоров по сетевым соединениям может замедлить извлечение данных, даже если запрос выполняется очень быстро.

Если вы хотите получить большие объемы данных очень быстро, вам нужно будет использовать CursorLocation = adUseClient в вашем соединении. Это означает, что у вас будет только статический локальный курсор, поэтому вы не будете получать обновления от других пользователей.

Однако - если вы только читаете данные, вы сохраните ADO, возвращаясь к БД для каждой отдельной записи, чтобы проверить изменения.

Я недавно изменил это, поскольку у меня была простая петля, заполняющая элемент списка, и каждый цикл занимал около 0,3. Не замедлиться, но даже на 1000 записей, что за 30 секунд! Изменение только местоположения курсора позволяет завершить весь процесс менее чем за 1 секунду.

Смежные вопросы