views:

3140

answers:

5

I have a 2 MB file, not too large, that I'd like to put into an sqlite database so that I can search it. There are about 30K entries that are in CSV format, with six fields per line. My understanding is that sqlite on the iPhone can handle a database of this size.

I have taken a few approaches but they have all been slow > 30 s. I've tried:

1) Using C code to read the file and parse the fields into arrays.

2) Using the following Objective-C code to parse the file and put it into directly into the sqlite database:

NSString *file_text = [NSString stringWithContentsOfFile: filePath usedEncoding: NULL error: NULL];

NSArray  *lineArray = [file_text componentsSeparatedByString:@"\n"];

for(int k = 0; k < [lineArray count]; k++){
 NSArray *parts = [[lineArray objectAtIndex:k] componentsSeparatedByString: @","];

 NSString *field0       = [parts objectAtIndex:0];
 NSString *field2       = [parts objectAtIndex:2];
 NSString *field3       = [parts objectAtIndex:3];

NSString *loadSQLi = [[NSString alloc] initWithFormat: @"INSERT INTO TABLE (TABLE, FIELD0, FIELD2, FIELD3) VALUES ('%@', '%@', '%@');",field0, field2, field3];


 if (sqlite3_exec (db_table, [loadSQLi  UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) {
  sqlite3_close(db_table);
  NSAssert1(0, @"Error loading table: %s", errorMsg);
 }

Am I missing something? Does anyone know of a fast way to get the file into a database?

Or is it possible to translate the file into a sqlite format that can be read directly into sqlite?

Or should I turn the file into a plist and load it into a Dictionary? Unfortunately I need to search on two of the fields, and I think a Dictionary can only have one key?

Jim

+1  A: 

I think you are confused about waht sqlite3 is. Sqlite3 is not an in memory database, it is a persistent disk based database, if you are loading all your data into every time you are doing something wrong. SQLite is designed for persistence, after you enter all the data into it you can just close the db, and the next time you open it using sqlite3_open_v2(), no need to reload all the data. By default sqlite3 does all its commits atomically (which is part of why the inserts are slow), so you don't even technically need to close it (though you still should, just to be safe, or in case you want to try to improve performance by using transactions).

In fact, rather than including a the CSV file with the app you could generate the sqlite3 database from the CSV file as part of your build process and include that with the app.

Louis Gerbarg
A: 

Louis, thanks for your response.

I should have mentioned that I only want to write the data into the database once at the beginning of the app, and then later I only need to do reads of the database, no writes.

Can you tell me how to generate the sqlite3 database directly from the CSV file as part of the build process?

James Testa
This should be a comment on his question, but you can create a simple helper command-line application that takes in the CSV and outputs a complete SQLite database file. If the CSV is changing throughout your development process, you can have this conversion take place within a Run Script build phase in Xcode. You can then copy in the database as a resource and use it from your iPhone application as a read-only database.
Brad Larson
Brad, Could you provide some code showing how this helper command-line application works? Would this be sqlite code?
James Testa
+1  A: 

OK, I think I've got it. Starting from the Unix command prompt the following reads in the CSV file and writes out a SQL file:

 % sqlite3
 sqlite3> .mode csv
 sqlite3>  create table NEWTABLE (ITEM_ID INTEGER PRIMARY KEY, FIELD0 TEXT, FIELD1 TEXT, FIELD2 TEXT, FIELD3 TEXT, FIELD4 TEXT, FIELD5 TEXT);
 sqlite3> .import csvfile.csv NEWTABLE
 sqlite3> .output csvfile.sql
 sqlite3> .dump NEWTABLE

The part I still haven't figured out is if there is a quick way to read the sql file into sqlite3. The approach I currently have is to read each line of the sql file and execute on the iPhone. Is there a one line approach to reading the sql file into sqlite3?

James Testa
You don't want to dump the file. That gives you a serialized series of SQL statements that can be used to recreate a database, not a database itself. Just run sqlite3 a path and it will create the db file there "sqlite3 /path/to/my/db" . If that file is human readable it is not what you want.
Louis Gerbarg
Louis, can you tell me the command that performs "run sqlite3 a path"?Thanks.
James Testa
Do you mean something like: % sqlite3 newdatabase.sqlite < newdatabase.sql
James Testa
The current problem I have when I execute % sqlite3 newdatabase.sqlite < newdatabase.sqlis that the complete database doesn't get written out to newdatabase.sqlite. Only about 3400 of the 33,000 lines get written to newdatabase.sqlite. Can anyone tell me why?
James Testa
I got newdatabase.sqlite to read correctly in the iPhone after deleting the iPhone's local copy.
James Testa
A: 

Thanks a lot for posting your solutions James. I was going through a similar problem of loading a large database file into sqlite3. Loading directly from a csv file is so much easier.

AKSA
+1  A: 

Ugh... don't deal with the C API yourself. Especially not when there are nicer wrappers available: http://cocoaheads.byu.edu/resources/sqlite

Dave DeLong