Передача таблицы rrecordset на сервер SQL - PullRequest
0 голосов
/ 21 ноября 2019

Добрый день, эксперты!

Я столкнулся с совершенно другим типом проблемы, чем обычно. Раньше я передавал на сервер одну строку через «Pass through Query», и иногда, когда мне нужно было передать более одной записи, я использовал функцию цикла для многократной отправки данных на сервер. Однако, если у меня более 40 строк записи, этот цикл займет значительное время. Мне просто интересно, есть ли способ отправить таблицу на сервер за 1 ход вместо числа ходов X с помощью цикла.

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

Dim db As dao.Database
Dim rs As dao.Recordset
Dim qdf As dao.QueryDef
Dim strSQL As String

Set db = CurrentDb
Set rs = Me.Recordset

rs.MoveLast
rs.MoveFirst

Do While Not rs.EOF
Set qdf = db.QueryDefs("Qry_Send_ClientData") 'local pass through query

strSQL = "EXEC dbo.SP_Client_Referral @JunctionID='" & Me.ClientID & "', @Note='" & Replace(Me.Txt_Note, "'", "") & "', @Value1='" & Txt_Value1 & "', @Value2='" & Txt_Value2 & "'"

qdf.SQL = strSQL
db.Execute "Qry_Send_ClientData"

rs.MoveNext
Loop

Msgbox "All Client Added!", , "Add client"

Теперь на стороне сервера SQL у меня есть следующая процедура хранилища (dbo.SP_Client_Referral), которая получает данные от сквозного запроса и вставляет строкукод для конкретной таблицы

    @ClientID AS NVARCHAR(15),
    @Note As NVARCHAR(500),
    @Value1 As NVARCHAR(50),
    @Value2 As NVARCHAR(50)
AS  

BEGIN

    SET NOCOUNT ON;

        BEGIN
        INSERT INTO dbo.Client_Data(ClientID, Note, Value_1, Value_2)
        SELECT @ClientID, @Note, @Value1, @Value2
        END

END

Для отдельной записи или даже до 10 записей этот метод является относительно быстрым. Однако по мере увеличения количества записей необходимое время может быть довольно продолжительным. Если есть способ передачи таблицы (т.е. стороны доступа с использованием SELECT * из LocalTable) на сервер SQL, в отличие от строки за строкой, это определенно сэкономит довольно много времени. Просто интересно, существует ли этот метод, и если да, то как мне отправить таблицу и что я должен использовать на стороне сервера SQL в SP, чтобы получить запись таблицы. В качестве альтернативы мне, возможно, придется продолжать использовать этот однострочный метод и, возможно, сделать его более эффективным, чтобы он выполнялся быстрее.

Большое спасибо заранее за вашу помощь!

Ответы [ 2 ]

0 голосов
/ 25 ноября 2019

На самом деле, самый быстрый подход?

Ну, это тот, который кажется ОЧЕНЬ противоречивым, и я мог бы ОЧЕНЬ долго объяснять, почему. Однако, попробуйте это, вы обнаружите, что он работает в 10 раз или лучше, чем у вас сейчас. Фактически, это может быть ближе к 100x, чем у вас.

Мы будем предполагать, что у нас есть стандартная связанная история к dbo.Client_Data. Скорее всего, ссылка Client_Data, или даже dbo_Cliet_Data.

Итак, используйте это:

Dim rs      As DAO.Recordset
Dim rsIns   As DAO.Recordset

If Me.Dirty = True Then Me.Dirty = False  ' write any pending data

Set rsIns = CurrentDb.OpenRecordset("dbo_Client_Data", dbOpenDynaset, dbSeeChanges)

Set rs = Me.RecordsetClone
rs.MoveFirst

Do While Not rs.EOF
   With rsIns
      .AddNew
      !ClientID = rs!ClientID
      !Note = Me.Txt_Note
      !Value_1 = Me.Txt_Value1
      !Value_2 = Me.Txt_Value2
      .Update
   End With

   rs.MoveNext
Loop
rsIns.Close
MsgBox "All Client Added!", , "Add client"

Обратите внимание на количество бонусов выше. Наш код чистый - нам НЕ нужно беспокоиться о типах данных, таких как даты, или о проблеме из-за вашей грязной цитаты. Если бы даты были включены, мы снова могли бы просто назначить, не беспокоясь о разделителях. Мы также получаем бонус защиты от инъекций при загрузке!

Мы также использовали me.RecordSetClone. Это не обязательно делать. Это поможет повысить производительность, но наиболее значительным является то, что при перемещении указателя записи позиция записи формы не пытается следовать. это избавит от большого количества мерцания. Это также может устранить ОГРОМНЫЕ проблемы, если в этой форме существует текущее событие.

Так что, хотя ОЧЕНЬ хорошая идея (recordsetclone), она не является главной причиной значительного увеличения производительности, которое вы увидите здесь. RecordSetClone - это то же самое, что и me.RecordSet, но вы можете "перемещать" и проходить через набор записей без указания главной формы.

Так что, действительно, самый "базовый" подход кода и тот, который будетработа скажем, доступ без SQL Server оказывается лучшим подходом. Это меньше кода, меньше грязного кода, и избавит вас от всех хлопот, чтобы настроить + построить хранимую процедуру SQL Server. Все ваши концепции были не нужны, и хуже всего они повлекут за собой снижение производительности. Попробуйте приведенную выше концепцию.

Access будет объединять и управлять несколькими вставками за один раз. Концепция и идея о том, что всегда использовать команды обновления / вставки SQL по сравнению с reocrdsets, является ДЕЙСТВИТЕЛЬНО ОГРОМНЫМ городским мифом, к которому стремятся многие разработчики доступа. Это не верно. В действительности проблема заключается в том, что если вы можете заменить цикл VBA огромного числа, скажем, отдельных выполненных обновлений, на ОДИН единый оператор обновления SQL, тогда да, вы на много километров вперед (чтобы использовать одно обновление SQL поверх некоторого цикла VBA).

Однако, если вам нужно выполнить несколько операций, и каждая операция находится в одной строке? Вместо «множества отдельных» обновлений SQL, а в этом случае (будучи) в подавляющем большинстве случаев, набор записей будет вращаться вокруг целого ряда отдельных команд обновления / вставки для достижения той же цели. Это даже близко, и вы получите в 10, если не в 100 раз лучшую производительность, используя вышеуказанные концепции.

0 голосов
/ 21 ноября 2019

Вы можете попробовать передать данные XML в хранимую процедуру.

DECLARE @rowData XML

SELECT @rowData = '<data><record clientid="01" Notes="somenotes" Value1="val1" Value2="val2" /><record clientid="02" Notes="somenotes 2" Value1="val1-2" Value2="val2-2" /></data>'

SELECT X.custom.value('@clientid', 'varchar(max)'),
    X.custom.value('@Notes', 'varchar(max)'),
    X.custom.value('@Value1', 'varchar(max)'),
    X.custom.value('@Value2', 'varchar(max)')
FROM @rowData.nodes('/data/record') X(custom)
...