Почему запросы SQL с функцией VBA выполняются так медленно? - PullRequest
0 голосов
/ 17 января 2011

Я унаследовал приложение, которое выполняет следующий вид запросов во многих местах:

select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = getFooF4()

getFooF4 выглядит так

Public Function getFooF4()
Dim dbCurrent As Database
Dim rstBar As Recordset

    Set dbCurrent = CurrentDb
    Set rstBar = dbCurrent.OpenRecordset("Bar", _
                                            dbOpenDynaset, _
                                            dbSeeChanges)
    getFooF4 = rstBar![myF4]
    ''yes this appears broken... Bar only contains one row :-/

    rstBar.close
    Set rstBar = Nothing
    dbCurrent.close
    Set dbCurrent = Nothing    
End Function
'' Note: in my experimentation getFooF4 only runs once during the 
''       execution of the query.

Это заканчивается довольно медленно. Если я удалю getFooF4 () из запроса с константой:

select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = 123456

или параметр:

select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = [myFooF4]

или с объединением:

select foo.f1, foo.f2, foo.f3
from foo
INNER JOIN bar ON bar.myF4 = foo.f4

Он работает намного быстрее.

Почему?

Характеристики: Приложение, написанное и работающее в MS Access 2003, внутренняя база данных - SQL Server 2008.

Ответы [ 3 ]

4 голосов
/ 17 января 2011

Ваш образец с GetFooF4 не может быть оптимизирован ни Sql Server, ни Access. И повторное открытие этого rs все время очень неэффективно. Как правило, избегайте использования специальных функций или кода Access в своих запросах. Это не позволяет Acces отправлять запрос «как есть» на сервер SQL. Вместо этого он должен загрузить весь пакет данных и обработать их локально, что означает больший трафик и меньшую скорость.
Смотри http://msdn.microsoft.com/en-us/library/bb188204(v=sql.90).aspx#optaccsql_topic2

2 голосов
/ 18 января 2011

Две вещи для повышения эффективности (хотя только один из них когда-либо будет применяться к конкретному случаю, подобному этому):

  1. определяет тип возвращаемого значения для вашей функции, т. Е. Public Function getFooF4() должно быть Public Function getFooF4() As Long (или любым другим подходящим типом данных. Без явного типа данных он возвращает вариант. В действительности, никогда не существует функция VBA, у которой когда-либо не должно быть декларации возвращаемого типа - если она возвращает вариант (что вполне разумно, особенно если в некоторых случаях нужно возвращать Null), определите его с помощью As Variant. Когда это какой-то другой тип данных явно определить его.

  2. объявляет параметр в вашем SQL, чтобы оптимизатор запросов мог использовать эту информацию при расчете плана запроса. Это не относится к случаю, когда ваше предложение WHERE использует функцию для предоставления критерия, но если вы использовали ссылку на поле в элементе управления, вы бы заменили это:

.

  select foo.f1, foo.f2, foo.f3
  from foo
  where foo.f4 = Forms!MyForm!MyControl

... с этим:

  PARAMETERS [Forms]![MyForm]![MyControl] Long;
  select foo.f1, foo.f2, foo.f3
  from foo
  where foo.f4 = Forms!MyForm!MyControl

Теперь, в любом из этих случаев, поскольку функция / параметр находится в предложении WHERE, ее необходимо разрешить только один раз, поэтому даже если функция неэффективна (как здесь, при инициализации переменной базы данных). и открытие набора записей), на самом деле это не будет иметь большого значения.

Еще одна вещь, которую стоит рассмотреть, - это заменить функцию простым DLookup (), который предназначен именно для этой цели. Кроме того, поскольку значение приходит из таблицы, вы можете присоединить его к таблице из одной строки:

  select foo.f1, foo.f2, foo.f3
  from foo INNER JOIN Bar ON foo.f4 = Bar.MyF4

Это было бы максимально оптимизировано оптимизатором запросов, поскольку в нем вообще нет неизвестных - оптимизатор запросов будет знать все, что ему нужно знать о типах данных и статистике таблиц, и сможет выбрать наиболее эффективный метод поиска из возможных.

1 голос
/ 17 января 2011

А как это сравнить с:

r = getFooF4()

select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = r

Если это так же медленно, как оригинал, то ответ прост: функция getFooF4 () - медленная часть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...