Почему запрос в списке доступа MS или поле со списком делает два вызова базы данных?

У меня есть форма с несколькими списками. В списках есть источник строки оператора SELECT из промежуточного запроса, который выполняет оператор EXEC для базы данных SQL.

Из-за проблем с производительностью мы наблюдали за сервером с помощью SQL Server Profiler и заметили, что когда вы запускаете.Requery для списка в коде VBA, он фактически выполняет оператор TSQL EXEC дважды. Я шаг за шагом прошел по коду VBA и доказал, что это одна строка кода (listbox.requery), которая создает множественные вызовы.

Кто-нибудь сталкивался с этим и / или получил какие-либо идеи решения.

Для дальнейшего пояснения источник строк в окне списка установлен на "SELECT * FROM qsptTestQuery". У меня есть объект запроса Access (названный, например, qsptTestQuery), который представляет собой сквозной запрос, который возвращает строки. в коде vba я устанавливаю.SQL этого объекта в 'Exec spTestProc 1234' и затем запускаю listbox.requery. когда я запускаю строку кода listbox.requery, он запускает 2 вызова в профилировщике.

1 ответ

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

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

Ниже приведен пример из старого приложения, в котором содержатся некоторые мои комментарии, которые, я надеюсь, будут полезны при написании ваших собственных. Мне приходилось использовать это только один раз (из многих, многих элементов управления ListBox и ComboBox), но это работало хорошо.

Private Function ListBoxResult(Ctr As Control, ID As Variant, Row As Variant, Col As Variant, code As Variant) As Variant
  '* listActionItems.[Row Source Type]
  '* Called to populate listActionItems

  '* PARAMETERS:
  '* Ctr:  A control variable that refers to the list box or combo box being filled.
  '* Id:   A unique value that identifies the control being filled. This is useful when you want to use the same user-defined function for more than one list box or combo box and must distinguish between them. (The example sets this variable to the value of the Timer function.)
  '* Row:  The row being filled (zero-based).
  '* Col:  The column being filled (zero-based).
  '* Code: An intrinsic constant that specifies the kind of information being requested.

  '* https://msdn.microsoft.com/en-us/library/office/ff845731.aspx
  '* Microsoft Access calls your user-defined function once for acLBInitialize, acLBOpen, acLBGetRowCount, and acLBGetColumnCount. It initializes the user-defined function, opens the query, and determines the number of rows and columns.
  '* Microsoft Access calls your user-defined function twice for acLBGetColumnWidth — once to determine the total width of the list box or combo box and a second time to set the column width.
  '* The number of times your user-defined function is called for acLBGetValue and acLBGetFormat to get list entries and to format strings varies depending on the number of entries, the user's scrolling, and other factors.
  '* Microsoft Access calls the user-defined function for acLBEnd when the form is closed or each time the list box or combo box is queried.
  '* Whenever a particular value (such as the number of columns) is required, returning Null or any invalid value causes Microsoft Access to stop calling the user-defined function with that code.

  Static days As Integer
  Static dt As Date
  Static result As Variant

  Select Case code
    Case acLBInitialize '0
      '* Return Nonzero if the function can fill the list; False (0) or Null otherwise.

      result = True
    Case acLBOpen '1
      '* Return Nonzero ID value if the function can fill the list; False or Null otherwise.
      result = True

    Case acLBGetRowCount '3
      If rsTemplateActions Is Nothing Then
        result = 0
      Else
        On Error Resume Next
        result = rsTemplateActions.RecordCount
        If Err.number <> 0 Then
          result = 0
        End If
      End If

    Case acLBGetColumnCount '4
      '* Columns: Action Type, Scheduled Date, Description, Priority
      result = 5

    Case acLBGetColumnWidth '5
      '* 1440 is twips per inch; -1 is default
      Select Case Col
        Case 0: result = 1.5 * 1440
        Case 1: result = 0.8 * 1440
        Case 2: result = 1# * 1440
        Case 3: result = 1.8 * 1440
        Case 4: result = 0.6 * 1440
        Case Else
          result = -1
      End Select

    Case acLBGetValue '6
      result = "-"

      If Not rsTemplateActions Is Nothing Then
        On Error Resume Next
        rsTemplateActions.MoveFirst
        If Err.number = 0 Then
          If Row > 0 Then rsTemplateActions.Move Row

          Select Case Col
            Case 0 'Action Type
              result = rsTemplateActions![Type Text]
            Case 1
              days = 0
              If IsNumeric(rsTemplateActions![DaysAdded]) Then
                days = rsTemplateActions![DaysAdded]
                result = "+" & days & " days"
              Else
                result = "?"
              End If
            Case 2 'Scheduled Date
              days = 0
              If IsNumeric(rsTemplateActions![DaysAdded]) Then
                days = rsTemplateActions![DaysAdded]
              End If
              If IsDate(txtActionDate.value) Then
                dt = CDate(txtActionDate.value)
                dt = DateAdd("d", days, dt)
                result = Format(dt, "mm/dd/yyyy")
              Else
                result = "?"
              End If
              Err.Clear
            Case 3 'Descrip
              result = rsTemplateActions!Description
            Case 4 'Priority
              result = ActionPriority(rsTemplateActions!Priority)
          End Select
        End If
      End If

    Case acLBGetFormat '7
      '* 1440 is twips per inch
      Select Case Col
        Case Else
          result = -1 'Default format
      End Select

    Case acLBEnd '9
      '* Only called when form is closed, not for each requery (I suppose for closing resources)
      'On Error Resume Next

    'Case acLBClose '8
    '  'NOT USED according to online resources.
    'Case Else
    '  Debug.Print "ListBoxResult Code = " & Code
  End Select

  ListBoxResult = result

End Function
Другие вопросы по тегам