Any way to speed up this Access DB process?

H

Hexman

Hi all,

I've written a vb.net 2005 app that uses an Access 2000 db. There are
2 tables used in this particular procedure. Table 1 has 9,870
"transaction" rows. Table 2 is like a "master" table and has 15,000
rows.

It takes 16 minutes to process the 9,870 rows. (debug mode on an AMD
3100+, with fast drives). That's about 615 transactions per minute.
Its no slouch, but this is only the test tables. My machine never
shows more than 15% cpu utilization during execution.

After conversion, there will be approximately 1,000 of these
transactions per day, but I have several other procedures that will
match and update as this procedure does. So I want to speed it up as
much as I can without increasing complexity of the code or using
non-standard methods.

I'm really only sweating the conversion process. I'll have 75,000
transactions, but will have 1.25 million rows to update with info from
3 other tables. Calculated out that seems to be about 100 hours. I
know there are other ways to do the conversion, but just want to find
an efficient way to accomplish this process.

Everything is done in code, not design mode. here is pseudo code:

---------------------------------------------------------------------------------------------------
new dataAdapter, connection, dt1, dt2
create select and update statements for dt1 & dt2
fill dt1 with transactions
loop thru dt1 rows
create dt2 select statement
fill dt2 with master (only 1 record)
if any rows selected
assign new cell values in dt2
adapter.update(dt2)
dt2 accept changes
dt2.clear() 'Clear out dt2
assign 'updated status code' to dt1 row
end if
end loop

adapter.update(dt1)
dt1.acceptChanges
close connection
dispose connection
----------------------------------------------------------------------------------------------------

The client will probably migrate to SQL, but right now the requirement
is for Access.

I need info on my coding methodology, like "you should create a new
dt2 within the loop rather than use dt2.clear()". Maybe there is a
faster way to search & update the equivalent of dt2 rather than using
a data table?

Something to think about, Thanks,

Hexman
 
C

Cor Ligthert [MVP]

Hexman,

To give us a better idea, what is the reason that you take everything in
memory, can you not use a where clause and get what you need? (Is the access
database on a Lan or is it local)

Cor
 
P

Patrice

Have you tried to use a SQL statement instead of doing this procedurally...

As a side note, SQL Server 2005 Express is free and Access is able to attach
to a SQL Server DB (dependiong the exact reason behind your customer
requirment)...
 
P

Paul Clement

¤ Hi all,
¤
¤ I've written a vb.net 2005 app that uses an Access 2000 db. There are
¤ 2 tables used in this particular procedure. Table 1 has 9,870
¤ "transaction" rows. Table 2 is like a "master" table and has 15,000
¤ rows.
¤

I would basically offer the same question as Patrice. However, it isn't clear to me from your
example exactly what you are doing.


Paul
~~~~
Microsoft MVP (Visual Basic)
 
H

Hexman

Cor,

I only read all the transactions (9,870 of them) into a data table
(dt1) at one time. As I loop thru each one of those, I generate a
parameterized select statement that is in effect saying "Select * from
dt2 WHERE dt2.Date = dt1.date, dt2.Category = dt1.Category". I'm only
selecting from dt2 where there is a match to key fields in dt1. I am
expecting only 1 dt2 record being selected for each transaction
record.

The Access database is local.

Hexman
 
H

Hexman

No, but I'd be willing to give it a try if I knew how to construct it.
Remember I have to update the transaction record indicatting that it
has updated a master record. I have to update the master with some of
the fields in the transaction. It might take some coding to get the
right result. I don't know how to write pure SQL statement that would
have to execute some kind of code during the update. Could you point
me in the direction of learning that method?

Client demands Access as many other of his "sub-systems" ar Access
based and he doesn't want to make any db changes at this time.

Hexman
 
H

Hexman

Paul,

I'm updating a "master" file with transactions. I'm updating each
transaction that was successfully process with a code that it was
processed.

Maybe, given a bit more time I can strip out the meaningful code and
it might give you a better idea of the process.

Hexman
 
C

Cor Ligthert [MVP]

Hexman,

Are you sure that this process needs a datatable. What I mean, are you not
better of with a datareader and process each tranaction one at a time in
your other database table?

Just a thought based on your given information until now.

Cor
 
H

Hexman

As I understand it (limited) that a datareader is read-forward only.
In my app, I update the "transaction" with an indicator that indicates
it has been successfully processed.

Later on in the app stream an "Archive" procedure scans various tables
(the transaction table being one of them) and selects processed
transactions to be retained for an audit trail.

Hexman
 
P

Paul Clement

¤ Paul,
¤
¤ I'm updating a "master" file with transactions. I'm updating each
¤ transaction that was successfully process with a code that it was
¤ processed.
¤

OK, but could you be a bit more specific? Does this mean you're attempting to update one table from
another table? How are these tables related? Do they have the same structure?


Paul
~~~~
Microsoft MVP (Visual Basic)
 
H

Hexman

Paul,

Here is a somewhat stripped down version of my routine that I'd like to speed up the process. Possibly this will make it clearer as to what I'm
trying to accomplish.

Critiique welcome.

Hexman



Imports System.data.oledb
Public Class Form1
Friend WithEvents cmdSelectBI As New OleDbCommand
Friend WithEvents cmdInsertBI As New OleDbCommand
Friend WithEvents cmdUpdateBI As New OleDbCommand
Friend WithEvents cmdDeleteBI As New OleDbCommand
Friend WithEvents daBI As New OleDbDataAdapter
Friend WithEvents cmdSelectEN As New OleDbCommand
Friend WithEvents cmdInsertEN As New OleDbCommand
Friend WithEvents cmdUpdateEN As New OleDbCommand
Friend WithEvents cmdDeleteEN As New OleDbCommand
Friend WithEvents daEN As New OleDbDataAdapter
Public Sub New()

' This call is required by the Windows Form Designer.
InitializeComponent()

' Add any initialization after the InitializeComponent() call.
' Transaction Table Config
daBI = New OleDbDataAdapter
daBI.SelectCommand = cmdSelectBI
daBI.InsertCommand = cmdInsertBI
daBI.UpdateCommand = cmdUpdateBI
cmdUpdateBI.Parameters.Add("@BIStatus", OleDbType.Integer, 4, "BIStatus")
cmdUpdateBI.Parameters.Add("@BIDate", OleDbType.Date, 8, "BIDate")
cmdUpdateBI.Parameters.Add("@BICat", OleDbType.VarChar, 3, "BICat")
cmdUpdateBI.Parameters.Add("@BISubCat", OleDbType.Integer, 4, "BISubCat")
cmdUpdateBI.Parameters.Add("@BIGroup", OleDbType.VarChar, 8, "BIGroup")
daBI.DeleteCommand = cmdDeleteBI

' Category Master Table Config
daEN = New OleDbDataAdapter
daEN.SelectCommand = cmdSelectEN
cmdSelectEN.Parameters.Add("@ENDate", OleDbType.Date, 8, "ENDate")
cmdSelectEN.Parameters.Add("@ENCat", OleDbType.VarChar, 3, "ENCat")
cmdSelectEN.Parameters.Add("@ENSubCat", OleDbType.Integer, 4, "ENSubCat")
cmdSelectEN.Parameters.Add("@ENGroup", OleDbType.VarChar, 8, "ENGroup")
daEN.InsertCommand = cmdInsertEN
daEN.UpdateCommand = cmdUpdateEN
cmdUpdateEN.Parameters.Add("@ENMach", OleDbType.VarChar, 2, "ENMach")
cmdUpdateEN.Parameters.Add("@ENOper", OleDbType.VarChar, 5, "ENOper")
cmdUpdateEN.Parameters.Add("@ENFailType", OleDbType.VarChar, 22, "ENFailType")
cmdUpdateEN.Parameters.Add("@ENBegQty", OleDbType.Integer, 4, "ENBegQty")
cmdUpdateEN.Parameters.Add("@ENAccQty", OleDbType.Integer, 4, "ENAccQty")
cmdUpdateEN.Parameters.Add("@ENQCQty", OleDbType.Integer, 4, "ENQCQty")

cmdUpdateEN.Parameters.Add("@ENDate", OleDbType.Date, 8, "ENDate")
cmdUpdateEN.Parameters.Add("@ENCat", OleDbType.VarChar, 3, "ENCat")
cmdUpdateEN.Parameters.Add("@ENSubCat", OleDbType.Integer, 4, "ENSubCat")
cmdUpdateEN.Parameters.Add("@ENGroup", OleDbType.VarChar, 8, "ENGroup")
daEN.DeleteCommand = cmdDeleteEN
End Sub
Private Sub ProcessTrans()
Dim intRCnt As Integer
Dim Idx As Integer

Dim cn As New OleDbConnection
Dim dtBI As New DataTable
Dim dtEN As New DataTable
Dim strConnect = _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\MfgSales.mdb;Persist Security Info=False"
cmdSelectBI.CommandText = "Select * from BIData where BIStatus = 0 "
cmdSelectBI.Connection = cn
cmdUpdateBI.CommandText = "UPDATE `BIData` SET `BIStatus` = ? WHERE ((`BIDate` = ?) AND (`BICat` = ?) AND (`BISubCat` = ?) AND (`BIGroup` =
?))"
cmdUpdateBI.Connection = cn
cmdSelectBI.Connection.ConnectionString = strConnect

cmdSelectEN.CommandText = "SELECT ENDate, ENCat, ENSubCat, ENGroup, ENMach, ENQCQty, ENOper, ENBegQty, ENFailType, ENAccQty FROM CatMast WHERE
((ENDate = ?) AND (ENCat = ?) AND (ENSubCat = ?)AND (`ENGroup` = ?))"
cmdSelectEN.Connection = cn
cmdUpdateEN.CommandText = "UPDATE `CatMast` SET `ENMach` = ?, `ENOper` = ?, `ENFailType` = ?, `ENBegQty` = ?,`ENAccQty` = ?, `ENQCQty` = ?
WHERE ((`ENDate` = ?) AND (`ENCat` = ?) AND (`ENSubCat` = ?) AND (`ENGroup` = ? ))"
cmdUpdateEN.Connection = cn
cmdSelectEN.Connection.ConnectionString = strConnect

intRCnt = daBI.Fill(dtBI)

For Idx = 0 To intRCnt - 1
cmdSelectEN.Parameters("@ENDate").Value = dtBI.Rows(Idx).Item("BIDate")
cmdSelectEN.Parameters("@ENCat").Value = dtBI.Rows(Idx).Item("BICat")
cmdSelectEN.Parameters("@ENSubCat").Value = dtBI.Rows(Idx).Item("BISubCat")
cmdSelectEN.Parameters("@ENGroup").Value = dtBI.Rows(Idx).Item("BIGroup")
intRCnt = daEN.Fill(dtEN)

if intRCnt <> 0 Then
' Calls to other subs to do calculations and lookups right here
dtEN.Rows(0).Item("ENMach") = dtBI.Rows(Idx).Item("BIMach")
dtEN.Rows(0).Item("ENOper") = dtBI.Rows(Idx).Item("BIOper")
dtEN.Rows(0).Item("ENFailType") = dtBI.Rows(Idx).Item("BIFailType")
dtEN.Rows(0).Item("ENBegQty") = TotBegQty
dtEN.Rows(0).Item("ENAccQty") = TotAccQty
dtEN.Rows(0).Item("ENQCQty") = TotQCQty
' Additional columns updated here
Try
daEN.Update(dtEN)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
dtEN.AcceptChanges()
dtEN.Clear()
dtBI.Rows(Idx).Item("BIStatus") = 20
End If
Next
Try
daBI.Update(dtBI)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
dtBI.AcceptChanges()
cn.Close()
cn.Dispose()
End Sub
End Class
 
C

Cor Ligthert [MVP]

Hexman,

As soon as you have this kind of code in your program (as you showed), than
you real should refactor it statement by statement.
dtEN.AcceptChanges()
dtEN.Clear()

This means that you first let the program set all rowstates of the rows in
the table to "not changed" and remove all changed original rows and than
remove all rows from the tables.

Cor
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top