Приложение для обеспечения учета решений для клиентов


У меня есть приложение в VB6, который существует уже более 7 лет, к которому у меня есть несколько клиентов, использующих его для своих учетных решений. Теперь моя проблема заключается в том, что конкретного клиента вырос такой большой размер базы данных 15Гб, регистр таблицы базы данных более чем 4 миллионов строк, размер поддержки из более чем 100 000, и т. д.

У меня есть код в приложение, где клиенты списана фиксированная ставка после проверки некоторых параметров, для клиента с небольшим или средним базе. Он работает просто отлично, но для этого конкретного клиента, этот код иногда даже не полный в 6 часов. Я искренне ищу помощь в решении моей Do Until петли головная боль. Есть ли способ, чтобы оптимизировать этот код и устранить Do Until заявление или сделать его работать быстрее?

TT1 = "GOODS%"
GClass = "10"
Shuss = "Interest Declaration"

Set rst = HConn.Execute("Select * from tblCInterest where AccID like '" & TT1 & "' order by AccID")
If rst.BOF Then
   MsgBox " There Is No Existing Account Under That Type", vbInformation
   Exit Sub
Else

Set rstd = HConn.Execute("Select count(*) as Countss from tblCINT where AccID like '" & TT1 & "'")
If rstd.EOF Then
Else
Label6.Caption = rstd!Countss
End If

Set rstG = HConn.Execute("select Balw from tblSerialCount")
If rstG!Balw = "" Then
   MsgBox " You Have Not Setup The Percentage", vbInformation
   Exit Sub
Else
End If

Set rstB = HConn.Execute("select srefno from tblSerialNo2")
If rstB!srefno = 0 Then
   MsgBox " You Have Not Setup The Parameter For Maximum Sales in a Month Per Customer !", vbInformation
   Exit Sub
Else
End If

Set rst2 = HConn.Execute("Select * from tblSerialNumbers")
DPP = Val(rst2!Int1) + 1
Trump = "INT" & GClass & "/" & Val(rst2!Int1) + 1

DAF:
Set rst2T = HConn.Execute("Select * from tblLedger where GREF = '" & Trump & "'")
If rst2T.BOF Then
Else
DPP = Val(DPP) + 1
Trump = "INT" & GClass & "/" & DPP
GoTo DAF
End If

HConn.Execute ("update tblSerialNumbers set Int1 ='" & Val(DPP) & "'")

Muka = Trump
GD = Trump
OD1 = 0


On Error GoTo ErrHandler
Do Until rst.EOF
BAL1 = 0
BAL2 = 0
PBar.Value = PBar.Value + 1
'INT
Joe = Val(Trim(Text1.Text)) / 100
Joe6 = Val(rst!CustBaL1)
Joe2 = Round(((Joe * rst!CustBaL1) / 12), 2)
'WHT
If Val(rstG!Balw) > 0 Then
TanG = "Total Tax For " & Dew2 & " " & Year(Date)
Tan6 = Val(rstG!Balw) / 100
Tan5 = Round(Val(Joe2) * Tan6, 2)
Else
TanG = "Total Tax on Interest Paid For " & Dew2 & " " & Year(Date)
Tan5 = 0
End If


Set rstB = HConn.Execute("select srefno from tblSerialNo2")
If rstB!srefno = 0 Then
Else
   Set rstc = HConn.Execute("select count(*) as Bety from tblSalesR where AccID = '" & rst!AccID & "' and Wmonth = '" & Joe4 & "' and Wyear = '" & Joe5 & "' ")
   If rstc!bety > Val(rstB!srefno) Then
      GoTo Dante
   Else
   End If
End If

Set rst15 = HConn.Execute("Select Blocked from tblClients where AccID = '" & rst!AccID & "'")
If rst15.BOF Then
GoTo Dante
Else
 if rst15!Blocked = "YES" then
    GoTo Dante
 else
 end if
end if

Set rst2 = HConn.Execute("Select * from tblClientInterest where Acctno = '" & rst!AccID & "' and period = '" & Month(Date) & "' and IntYear = '" & Year(Date) & "' ")
If rst2.BOF Then
Else
GoTo Dante
End If

Set rst15 = HConn.Execute("Select Bal101,CCode from tblClients where AccID = '" & rst!AccID & "'")
If rst15.BOF Then
GoTo Dante
Else

BAL1 = Val(rst15!Bal101)

'MINIMUM BALANCE SETUP
Set rstF = HConn.Execute("select Flopno from tblSerialNo2")
If Val(rstF!flopno) >= 0 Then
   If Val(BAL1) < Val(rstF!flopno) Then
      GoTo Dante
   End If
Else
GoTo Dante
End If

Joe3 = Round((Val(rst15!Bal101) + Joe2) - Tan5, 2)
Joe4 = Month(Date)
Joe5 = Year(Date)

BranchT = rst15!CCode
End If

If Val(Joe2) < 0 Then
   GoTo Dante
End If

'ELIMINATE ZERO BALANCE
If Val(BAL1) < 0 Then
   GoTo Dante
End If


Set rst11 = HConn.Execute("select * from tblAcctClasses where Acct='" & DataCombo1.Text & "' and Bcode = '" & BranchT & "'")
If rst11.BOF Then
MsgBox " The Client Type Does Not Exist In The Database ! ", vbInformation
GoTo Dante
Else
TT11 = rst11!ACCTCODE
TUID = rst11!ACCTCODE
End If



GOVAcct = rst!AccID
GOVRef = Muka


'INT
DBAL1 = Round(Val(BAL1), 2)
HConn.Execute ("insert into tblLedger values ('" & Replace(rst!ClientName, "'", "''") & "','" & rst!AccID & "','" & Replace(DataCombo1, "'", "''") & "','" & Year(Date) & "','" & Date & "','" & Shuss & "','" & Muka & "','0','" & Val(Joe2) & "','0','0','0','','" & Replace(PostUser, "'", "''") & "','" & Format(time, "HH:MM:SS Am/Pm") & "')")
BAL2 = Round(Val(BAL1) + Val(Joe2), 2)
HConn.Execute ("Update tblClients set Bal101='" & BAL2 & "' where AccID = '" & rst!AccID & "'")


If Val(DBAL1) >= 0 Then
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & TT11 & "','" & Replace(Shuss, "'", "''") & "','" & Muka & "','0','" & Val(Joe2) & "','" & Replace(PostUser, "'", "''") & "')")
ElseIf Val(DBAL1) < 0 Then
If Val(DBAL1) + Val(Joe2) <= 0 Then
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & C5 & "','" & Replace(Shuss, "'", "''") & "','" & Muka & "','0','" & Val(Joe2) & "','" & Replace(PostUser, "'", "''") & "')")
GOVVal = Val(Joe2)
PERFCHECK4
Else
CBAL1 = Val(DBAL1) * -1
CBAL2 = Round(Val(Joe2) + Val(DBAL1), 2)
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & TT11 & "','" & Replace(Shuss, "'", "''") & "','" & Muka & "','0','" & Val(CBAL2) & "','" & Replace(PostUser, "'", "''") & "')")
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & C5 & "','" & Replace(Shuss, "'", "''") & "','" & Muka & "','0','" & Val(CBAL1) & "','" & Replace(PostUser, "'", "''") & "')")
GOVVal = Val(CBAL1)
PERFCHECK4
End If
End If

HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & C6 & "','" & Shuss & "','" & Muka & "','" & Val(Joe2) & "','0','" & Replace(PostUser, "'", "''") & "')")


'TAX

BAL1 = Val(CustBaL1(rst!AccID))
BalTax = Val(BAL1)
BalTax2 = Round(Val(BalTax) - Val(Tan5), 2)

HConn.Execute ("insert into tblLedger values ('" & Replace(rst!ClientName, "'", "''") & "','" & rst!AccID & "','" & Replace(DataCombo1, "'", "''") & "','" & Year(Date) & "','" & Date & "','" & TanG & "','" & Muka & "','" & Val(Tan5) & "','0','0','0','0','','" & Replace(PostUser, "'", "''") & "','" & Format(time, "HH:MM:SS Am/Pm") & "')")
BAL2 = Round(Val(BAL1) - Val(Tan5), 2)
HConn.Execute ("Update tblClients set Bal101='" & BAL2 & "' where AccID = '" & rst!AccID & "'")


If Val(BalTax) <= 0 Then
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & C5 & "','" & TanG & "','" & Muka & "','" & Val(Tan5) & "','0','" & Replace(PostUser, "'", "''") & "')")
GOVVal = Val(Tan5)
PERFCHECK3
ElseIf Val(BalTax) > 0 And Val(BalTax2) < 0 Then
CBAL1 = Val(BalTax)
CBAL2 = Round(Val(Tan5) - Val(CBAL1), 2)
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & TT11 & "','" & TanG & "','" & Muka & "','" & Val(CBAL1) & "','0','" & Replace(PostUser, "'", "''") & "')")
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & C5 & "','" & TanG & "','" & Muka & "','" & Val(CBAL2) & "','0','" & Replace(PostUser, "'", "''") & "')")
GOVVal = Val(CBAL2)
PERFCHECK3
Else
HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & TT11 & "','" & TanG & "','" & Muka & "','" & Val(Tan5) & "','0','" & Replace(PostUser, "'", "''") & "')")
End If

HConn.Execute ("insert into tblBookLedgerTemp values('" & Year(Date) & "','" & Date & "','" & C24 & "','" & TanG & "','" & Muka & "','0','" & Val(Tan5) & "','" & Replace(PostUser, "'", "''") & "')")


HConn.Execute ("insert into tblClientInterest values ('" & Replace(rst!ClientName, "'", "''") & "','" & rst!AccID & "','" & Date & "','" & Joe2 & "','" & Joe4 & "','" & Year(Date) & "','" & Replace(PostUser, "'", "''") & "','" & Muka & "','')")


Dante:
rst.MoveNext

Loop

HConn.Execute ("insert into tblClientInterestdone values('" & Month(Date) & "','" & Year(Date) & "','" & Replace(PostUser, "'", "''") & "','" & DataCombo1.Text & "')")
End If


'SECOND SET

Set rst15 = HConn.Execute("Select distinct AccID as AccID from tblBookLedgerTemp order by AccID ")
If rst.BOF Then
Else
Do Until rst15.EOF

Set rst16 = HConn.Execute("Select sum(credit) - sum(debit) as Bal from tblBookLedgerTemp where AccID = '" & rst15!AccID & "'")
AB1 = Round(IIf(IsNull(rst16!Bal), 0, rst16!Bal), 2)

Set rst2 = HConn.Execute("Select * from tblBookLedgerTemp Where AccID = '" & rst15!AccID & "' ")
Shuss = Mudas '& " " & DataCombo1.Text

If Val(AB1) > 0 Then
   HConn.Execute ("Insert into tblBookLedger values ('" & rst2!gPeriod & "','" & rst2!PostDate & "','" & rst15!AccID & "','" & Replace(Shuss, "'", "''") & "','" & rst2!GREF & "','0','" & Val(AB1) & "','" & rst2!Puser & "')")
ElseIf Val(AB1) < 0 Then
   HConn.Execute ("Insert into tblBookLedger values ('" & rst2!gPeriod & "','" & rst2!PostDate & "','" & rst15!AccID & "','" & Replace(Shuss, "'", "''") & "','" & rst2!GREF & "','" & Val(AB1) * -1 & "','0','" & rst2!Puser & "')")
Else
End If

rst15.MoveNext
Loop
End If


MsgBox " The Interest Have Been Completed !", vbInformation


270
5
задан 3 февраля 2018 в 03:02 Источник Поделиться
Комментарии
1 ответ

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

Производительности

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

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

Вторая причина для этого заключается в том, что базы данных гораздо лучше оптимизирован для сопоставления данных, чем ваш цикл. Цикл по одной таблице, а потом искать соответствующее значение в другой таблице есть спектакль \$о(Нм)\$, что не то, что вы хотите для больших таблиц. Слияния и хэш-соединений, баз данных, использовать гораздо лучше. Соединение слиянием примет \$за o(n журнал(N) + М журнал(м))\$ в худших условиях, например, без индексов и без заказ.

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

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

SELECT 
CI.AccId,
CI.CustBal1,
C.Bal101,
A.ACCTCODE
FROM tblCInterest AS CI
INNER JOIN tblClients AS C
ON CI.AccId = C.AccId
AND C.Blocked <> 'YES'
AND C.Bal101 >= 0
INNER JOIN tblSerialNo2 AS S
ON C.Bal101 >= S.flopno
AND (srefno = 0
OR srefno <= (SELECT COUNT(*)
FROM tblSales AS Sa
WHERE Sa.AccId = C.AccId
AND Wmonth = Joe4
AND Wyear = Joe5)
INNER JOIN tblAcctClasses AS A
ON C.CCode = A.BCode
AND B.Acct = Datacombo1.Text
LEFT JOIN tblClientInterest AS ClI
ON CI.AccID = ClI.AccNo
AND ClI.period = Month(Date)
AND ClI.IntYear = Year(Date)
WHERE ClI.AccNo IS NULL
AND CI.AccID LIKE 'GOOD%'
AND Round(CI.CustBal1*Trim(Text1.Text)/12, 2) >= 0

Обратите внимание, что я игнорировал любые потенциально необходимые слепки, так как я не имею понятия как переменные и столбцы.

Второй цикл также будет сокращенной. В этот раз первые два запроса могут выполняться одновременно с помощью GROUP BY положение о AccId. Если вы используете достаточно новую версию SQL Server, вы могли бы сделать все три сразу, используя агрегатные оконные функции. В противном случае, вы можете просто присоединиться к столу снова результату GROUP BY запрос.

(Почему-то, кажется, вы когда-нибудь использовали только первую строку из последнего запроса, который является немного странным.)

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

Одна другая вещь в этом отношении я нашел довольно часто в коде заключается в том, что вы вернуть все столбцы из всех совпадающих строк, просто чтобы проверить, что что-то есть. Вы можете просто выбрать постоянное значение NULL или 1, который не пожалеет на базе выборки что-нибудь из таблицы. Кроме того, вы можете просто извлечь первую строку или использовать EXISTS подзапрос.

Безопасности

В нескольких местах текст будет встроен в ваши строки запроса. Я надеюсь, что этот текст не вводится пользователем или тщательно обоснованы. Чтобы понять, почему это важно, просто погуглите SQL-инъекции атаки или увидеть http://bobby-tables.com/ для быстрой справки.

Ремонтопригодность

Читая ваш код, я нашел несколько точек, где ремонтопригодности код может быть улучшен.

Самая первая вещь состоит в том, что отступ ваш код является довольно противоречивы. Правильные отступы могут очень сильно помочь сделать код более читабельным. Чтобы устранить вмятины, возможно, вы захотите посетить интернет - ВБА/в VB6 индентора. (Полное раскрытие - я участвую в проекте этот сайт принадлежит.)

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

Только не описательные имена, код очень значительно труднее понять, потому что вы никогда не объявлять переменные, которые вы используете. Для одного типа из соображений безопасности, объявление переменных-это уже хорошая идея.

Еще одна особенность в ваш код, что вы используете много If Then Else конструкции, где Then блок или Else блок пуст. В случае пустой Else блок, вы можете просто не писать Else С тем же эффектом, но выражены более отчетливо. В случае Then блок пустой, это будет хорошая идея, чтобы инвертировать условие. В итоге вы Then и Else обменялись. Поскольку Else блок пуст, то, вы можете просто удалить его.

Другая вещь, которую я заметил, состоит в том, что код использует GoTo команды вне инструкции обработки ошибок. Это довольно сильно сбивает с толку и всегда можно ручками, не прибегая к GoTo. В частности, оно может быть преобразовано в Do While петли.

Наконец, мне показалось странным, что AccId кодирует тип счета. Это, конечно, лучше хранить в другом (проиндексированных (вместе с AccId)) столбце. Однако, это, конечно, ничего, что могло бы быть легко изменены после создания базы данных в производство.

Редактировать:

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

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

9
ответ дан 4 февраля 2018 в 02:02 Источник Поделиться