Link to home
Start Free TrialLog in
Avatar of 4ice
4ice

asked on

Fast way to insert 21000 rows in a SQLite database with C#

Hi all,

I need to import a text file in C# which contains 21000 rows. Each row contains 15 columns.

I tried different things, but it is extremely slow. This is the current code which is relevant:

SQLiteConnection _dbConnection = new SQLiteConnection("Data Source=smp.db;Version=3;New=True;Compress=True;");
_dbConnection.Open();
string[ ] lines = File.ReadAllLines(fileName);

foreach (string line in lines)
{
    string[ ] parts = line.Split(new string[ { ";" }, StringSplitOptions.None);

    sqlQuery = @"INSERT INTO testtable VALUES (" + parts[0] + "," +
                             parts[1] + "," +
                            "'" + parts[2] + "'," +
                            parts[3] + "," +
                            "'" + parts[4] + "'," +
                            parts[5] + "," +
                            "'" + parts[6] + "'," +
                            "'" + parts[7] + "'," +
                            parts[8] + "," +
                            "'" + parts[9] + "'," +
                            "'" + parts[10] + "'," +
                            "'" + parts[11] + "'," +
                            "'" + parts[12] + "'," +
                            parts[13] + "," +
                            "'" + parts[14] + "'); ";
    SQLiteCommand cmd = new SQLiteCommand();
    cmd.Connection = _dbConnectie;
    cmd.CommandText = sqlQuery;
    cmd.ExecuteNonQuery();
}

I have done the same thing before in vb.NET and with a msaccess database and that worked pretty fast.
if I leave out the execute part, it's done in about 1 second. Off course this is not surprising, but I just wanted to make sure it was an insert problem.

Does anyone have a suggestion?
Avatar of pras_gupta
pras_gupta

You can try constructing all the insert statements into a script and then firing at once.
 http://www.vb-helper.com/howto_sql_script.html
 
Avatar of 4ice

ASKER

I'm not sure if this is what you mean, but from the SQLite website I copied the following:

"
Multi-row INSERT a.k.a. compound INSERT not supported.
INSERT INTO table (col1, col2) VALUES ('row1col1', 'row1col2'), ('row2col1', 'row2col2'), ...
"

I also tried:
    sqlQuery = sqlQuery + @"INSERT INTO testtable VALUES (" + parts[0] + "," +
                             parts[1] + "," +
                            "'" + parts[2] + "'," +
                            parts[3] + "," +
                            "'" + parts[4] + "'," +
                            parts[5] + "," +
                            "'" + parts[6] + "'," +
                            "'" + parts[7] + "'," +
                            parts[8] + "," +
                            "'" + parts[9] + "'," +
                            "'" + parts[10] + "'," +
                            "'" + parts[11] + "'," +
                            "'" + parts[12] + "'," +
                            parts[13] + "," +
                            "'" + parts[14] + "'); ";
But this hangs everything completely, and this is even without ExecuteNonQuery() (so only building the sqlQuery string)
A fairly significant problem here is the modifiability of your code. Instead, using a StringBuilder in the System.Text namespace would probably be more efficient. Every String you make is stored in memory until the GC re-claims it, and due to the immutability of Strings, this can take a fairly long time. Obviously, inserting 21,000 rows can really become a long process. I'll give an example of my suggestion. Let me know if it doesn't work/is not what you're looking for.
static System.String GetInsertCommand( System.String myFilePath )
{
	const System.Char COMMA = ',';
	const System.Char APOS = '\'';
	const System.Char DELIMITER = ';';
	System.Text.StringBuilder bldr = new 
System.Text.StringBuilder("INSERT INTO testtable VALUES(");
 
         // Use a StreamReader instead of ReadAllLines;
         // ReadAllLines will eat up your memory pretty bad.
	using(System.IO.StreamReader reader =
		new System.IO.StreamReader
                  (System.IO.File.OpenRead(myFilePath)))
	{
		while(!reader.EndOfStream)
		{
			foreach(System.String str in
                                reader.ReadLine().Split(DELIMITER))
			{
				bldr.Append(APOS);
				bldr.Append(str);
				bldr.Append(APOS);
				bldr.Append(COMMA);
			}
		}
	}
 
	bldr.Append(");");
	return bldr.ToString();
}

Open in new window

I was taking about the second approach, instead of using + , try using StringBuilder.
http://msdn.microsoft.com/en-us/library/system.text.stringbuilder(VS.71).aspx
 
Avatar of 4ice

ASKER

Although the StringBuilder is a better way to build my query, it seems to have no effect on the time.

The query itself is built in a split second, but after that I need to execute it and that's where it goes wrong.

An extra problem could be that my C# skills are below zero :)
Avatar of 4ice

ASKER

Well my problem is solved.

I did not started a transaction before. Now I added a 'begin transaction' before the loop and a 'commit' after the loop and the entire 21000 rows are inserted in only 3 seconds!!

Thanks for your help anyway guys!
Glad to hear it. I mainly suggest my method because it's much more manageable than the way I saw it otherwise implemented--the algorithm is dynamic. But, if you have need for it to not to be dynamic for whatever reason, my method would not be the wisest choice.

Anyways, hope we at least somewhat helped,

Nate
ASKER CERTIFIED SOLUTION
Avatar of ee_auto
ee_auto

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial