Click here to Skip to main content
15,881,559 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more: , +
Hi guys

I am developing a project using SQL server 2008 Express.
My project is a newer version of an existing program we developed earlier using Microsoft Access as a database.

What I want to do now is write a data conversion program so I can put the old data (Access) in the new datatabse (SQL). Some modifications are needed so no ipport to SQL is possible.

What I am doing so far is creating a connection to de Access database, writing an SQL command that will get the datat I want from the Access database and then fill a datatable with the result of that query.

When I have the datatable filled I can do whatever I want with the data before I insert it into SQL.

The problem that I am facing now is that I have to load a table with 130.000 records. I tried this in two different forms:

method 1
VB
Public Function ReadAccessTableContent(ByVal sqlq As String, ByVal db As String) As DataTable

       set_Access_Connection(db)
       Dim oledbcon As New OleDbConnection(strAccCon)
       Dim myOLEDBCommand As New OleDbCommand(sqlq, oledbcon)
       Dim dt As New DataTable

       dt.Clear()

       If oledbcon.State = ConnectionState.Open Then
           oledbcon.Close()
       End If

       oledbcon.Open()

       Using reader As OleDbDataReader = myOLEDBCommand.ExecuteReader((CommandBehavior.CloseConnection))
           Try
               dt.Load(reader)
           Catch ex As Exception
               MessageBox.Show(ex.Message)
           End Try
       End Using

       Return dt

   End Function


method 2
VB
Public Function ReadAccessTableContent2(ByVal sqlq As String, ByVal db As String) As DataTable

    set_Access_Connection(db)
    Dim oledbcon As New OleDbConnection(strAccCon)
    Dim myOLEDBCommand As New OleDbCommand(sqlq, oledbcon)
    Dim dt As New DataTable

    'dt.Clear()

    If oledbcon.State = ConnectionState.Open Then
        oledbcon.Close()
    End If

    oledbcon.Open()

    Dim adapter As New OleDbDataAdapter(myOLEDBCommand)
    adapter.Fill(dt)

    Return dt

End Function



Both of these functions just take forever to execute on the step dt.Load(reader) or adapter.Fill(dt).

Does anyone have any idea why this will not work? I let the program run for multiple hours but no results...

The data I wish to retrieve is straight forward, so no inner or outer joins, just simple data from 1 table....
Posted
Updated 18-Dec-13 5:55am
v2

Why to close connection, if a few lines down, connection is opened?
VB
If oledbcon.State = ConnectionState.Open Then
    oledbcon.Close()
End If
'here!
oledbcon.Open()


Please refer this: OleDbCommand Class[^] and have a look at code sample at the bottom of page.
 
Share this answer
 
v2
Comments
davy.lambrechts 18-Dec-13 18:11pm    
I wrote the if because I want to check if the connection is open or closed because I need this connection for other purposes also. If I try to open the connection when already opened you get an error.
Maciej Los 18-Dec-13 18:14pm    
Then check if it's closed ;)
130,000 rows is a lot to load in one go: I assume that you aren't trying to present this to the user directly!

There are a couple of things you can do to speed it up, but with that number of rows they probably aren't going to have a major effect - but they are simple. Start by looking at your query. Are you retrieving information you don't need? For example, 130,000 text fields of 100 characters each needs 13,000,000 bytes of bandwidth just to transfer, and an image field is going to be even bigger. If your query is
SQL
SELECT * FROM MyTable
Then you may be able to save significant time by fetching only the data you need.

There is also the option of "on-demand" loading - you fetch the minimum data necessary in one go (just the row IDs for example) and then only fetch the row detail when you actually need it. I use this system for images to good effect: On-demand loading of images from a database[^] (it's in C#, but it's pretty obvious what is going on)

The biggest performance improvement (from a user perspective) is the hardest to implement: move your loading code into a separate thread and retrieve row-by-row, updating as needed. It's not too complex to actually do this - a BackgroundWorker[^] is pretty simple - but it can mean substancial changes to other code, depending on how you are using things. I tend to try to load in the background at startup when the user isn't actually doing anything yet, if I can.
 
Share this answer
 
Comments
davy.lambrechts 18-Dec-13 18:10pm    
My query already consists of the fields I need, so no 'select * from' is used.
I also don't want to show 130.000 rows to a user. The thing I'm trying to do is get the data from a table in Access, put it in a datatable and then use this datatable to bulkcopy in an SQL server database table
OriginalGriff 19-Dec-13 11:31am    
Sorry for the late reply - this got lost in my emails the morning :O
Both the fill of the DataTable and the actual SqlBulkCopy are going to take time, and there really isn't a lot you can do about that - worse, the SQL side is always a monolithic operation so you can't speed that part up.
You way be able to gain some speed though, by utilizing a number of threads to do the job.
I'd have a go at doing it in ten chunks, using ten different threads using ten different SQLConnections (and possibly ten connections to the Access file, it should be able to cope since they would be read locks, not write locks).
You won't have ten cores free to run them all on, but that's ok - since most of teh time the threads will be stalled waiting for I/O operations or the SQL server to process things. With any luck, you should be able to get multiple connections filling different "block" of the SQL in separate threads on the SQL machine, while other threads on your computer are still filling Access data.
Worth a try - it shouldn't take too much work to set up a quick testbed DB and hack some code together to see if there is any improvement.

[edit]Typo "of" for "or" - OriginalGriff[/edit]
Suggestions

1. Who is going to see 13K records in a Page? So, limit your query to to return a small number of records.
2. Always mention the column names in the select query. Selecting by * would return all columns, but all of them might not be required.
3. As soon as the data are retrieved, close and dispose the database connections.
 
Share this answer
 
Comments
davy.lambrechts 18-Dec-13 18:11pm    
Hi guys, thanks for the responses.

My query already consists of the fields I need, so no 'select * from' is used.
I also don't want to show 130.000 rows to a user. The thing I'm trying to do is get the data from a table in Access, put it in a datatable and then use this datatable to bulkcopy in an SQL server database table.

As soon as the data is received: that's the problem, I get stuck on the 'receive data' part...
 
Share this answer
 
Comments
davy.lambrechts 19-Dec-13 3:18am    
Thanks for the help, but I'm already using the SQLBulkCopy command to insert my data into SQL Server.

This is not the problem. My problem occurs in the steps before, when I want to load my data into a .NET datatable so I can pass it to the SQLBulkCOpy command.

The command datatable.load(datareader) (where I want to load the Access table data using a select statement) takes all night to load a simple 130.000 records...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900