I want to insert a row in a table, and when I do the insertion I want to insert another row in another table at the same time.
What is the more efficient way to do this in an Android app?
Is it more efficient to do a trigger when I insert one row and SQL takes care of the insertion, or do two inserts with database.insert() in Java?
The information needed to insert the second row is already in the first insertion.
Thanks!
I want to insert a row in a table, and when I do the insertion I want
to insert another row in another table at the same time.
For sure use for this TRIGGER, because it working on database layer so you only need to create it and then it will be called itself when you do something(depends on how you implement trigger).
Also it's more faster and you do not call it explicit, just let database work. All what is database able to do, let do it on database.
Update:
So after a little discussion with #Graham Borland you can use also inserts in TRANSACTION.
Have look at Android Database Transaction.
And conclusion what is faster?
I exactly don't know it because i don't have performance tests but for sure TRANSACTIONS are the safest i think but whether faster than TRIGGERS this i don't know exactly but usage of transactions is very good and mainly safe approach to prevent database get to incorrect state that is very undesirable.
Related
I've got a table with about 7 million rows in it. I'm inserting on average about one row every second into the database. When I do this, I am noticing that it is taking an incredibly long time (as much as 15 seconds) to run a simple SELECT against the database, e.g. something like:
SELECT * FROM table WHERE rowid > 7100000
This select often returns no rows of data as sometimes no data has been inserted in this particular table. It is often happening even when the table I'm writing to isn't even actually inserting rows into the table I am reading.
The idea is that there are two separate processes, one is adding data, the other is trying to get all new data that has not yet been read. But the read side is connected to a UI and any noticable lag is intolerable, much less 15 seconds. This is being run under Android and the the UI thread doesn't like being blocked for that long either and it is wreaking havoc.
My initial thought was maybe the insert is requiring an update to the indicies as originally I had the index on a different field (a time field). This seems at least partially confirmed because if I use a database with only a few rows each select completes in a few milliseconds. But when I re-created the table to only have the rowid as primary key it actually got slower. I would expect inserting a new row at the end would always result in very fast reads when just comparing on the rowid as primary key.
I have tried enabling write ahead logging, but it appears that SQLCipher doesn't support this, at least not directly, as it doesn't adhere to the lastest API for android.database.sqlite.SQLiteDatabase. Even using "PRAGMA journal_mode = WAL" in the postKey hook hasn't made any difference.
What's going on here? How can I speed up my selects?
Update: I tried getting rid of sqlcipher and just using plain sqlite to see if that was a factor. I used sqlcipher_export to export to a plaintext database, and then used the default android.database.sqlite.SQLCipher. The delay time dropped from 10-20s to 1.8-2.8s. I then removed write-ahead and it dropped further to 1.3-2.7s. So the issue is still noticably there, although it did get a lot better.
SQLite is ultimately file-based, and there is no portable mechanism to communicate to another process which part of a file has changed. So when one process has written something, all other processes must drop their caches when they access the database file the next time.
If possible, modify your architecture that both parts of the code are in the same process and share the same database connection. (With multiple threads, this requires locking, but SQLite has not much concurrency anyway.)
Alternatively, write the new data into a separate database, and let the UI app move it to its own database.
I don't know why SQLCipher is so much slower (it's unlikely to be the CPU overhead of the decryption).
I am creating an Android app for which I need to create a SQLite DB and pre-populate it with some values.
The Android documentation says this about what to do in "onCreate" of the SQLiteOpenHelper:
Called when the database is created for the first time. This is where the creation of tables and the initial population of the tables should happen.
Reference - http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onCreate(android.database.sqlite.SQLiteDatabase)
I am doubtful about the following 2 things -
What is meant by "when database is created for the first time"? Is this done on the first launch of the app or only when the first DB request (read/write etc) is done.
If it is the latter, I fear that it may take quite some time to create DB, pre-populate it with values (I have about 60 rows to be inserted into 1 table) and then read the DB to show it. Is this the best practice?
I have been doing all my DB operations in AsyncTasks. But I am doing the table creations in onCreate using "db.execSQL" statements. Is this fine (in terms of convention/ performance) or should I go for an AsyncTask here as well?
Any help is appreciated.
1) The later. It is done on the first read or write to the DB.
Your fear might be correct, this is why you can ship your app with a database that's already populated. Or you can launch an AsyncTask with a simple SELECT 1 FROM anytable query. More about shipping with DB here. (60 rows is nothing to fear about tho, and you can safely just keep using AsyncTasks).
2) Yes it is fine. The onCreate logic will run when you first read/write the DB, so it if you always use AsyncTasks onCreate will run in an AsyncTask also.
What is meant by "when database is created for the first time"? Is this done on the first launch of the app or only when the first DB request (read/write etc) is done.
It happens when you first query from database in general term. After that only Upgrade method is called that too when you change the db version.
If it is the latter, I fear that it may take quite some time to create DB, pre-populate it with values (I have about 60 rows to be inserted into 1 table) and then read the DB to show it. Is this the best practice?
60 rows insertion is not a big task. More you can read about beginTransaction(),commitTransaction and endTransaction for insertion. It will make your insertion task lighting fast.
I have been doing all my DB operations in AsyncTasks. But I am doing the table creations in onCreate using "db.execSQL" statements. Is this fine (in terms of convention/ performance) or should I go for an AsyncTask here as well?
It good you are doing you Db operation in AsyncTask and its completely fine.
Speaking of DB operations:
Performing DB operations in AsyncTask is not a good approach, generally. As you might encounter a problem called "memory leak", and it might come as a silent assassin in the night.
There's lot written on this issue. Just google "asynctask leak context" and here you go.
So how to perform DB operations?
Using Loader API in conjunction with ContentProvider is considered good approach for querying database. Loader asynchronously queries your database and delivers the result to specified subscribers. Configuration changes or other sudden stuff does not bother it.
And it is really convenient to query your data using loader API once you know how to do it.
Single inserts/updates/deletes might be done directly from the main thread via ContentResolver. These calls will be blocking (synchronous), but I bet you user would never notice anything while the amount of data is not large.
If you're operating on a large dataset, and you fear you'll be significantly blocking UI thread, I'd suggest using IntentService or any custom Service capable of doing operations in background (note that by default Service operates on main UI thread and you have to specify background operation yourself or use IntentService)
Speaking of DB initialisation:
You might create a one-time IntentService, if you're initialising a large set of data. It will handle your request asynchronously and, for example, perform a broadcast that the application is set up and ready, so you might stop a "wait a sec, performing app initialisation" screen and show user your data.
There's also nothing wrong with shipping your database along with application, though it appears to be a bit hackish solution.
Either way, you choose what is more suitable for you.
I'm refactoring an Android work-in-progress app to use the Loader framework, and since the data is all stored in the SQLite database I'm using the commonsware loaderex package and SQLiteCursorLoader rather than a ContentProvider layer.
The insert(..), update(..) etc methods in SQLiteCursorLoader have void return type. It would make my life easier and my code neater if they returned a long, being the autoincremented row id of the row in the table that had been amended.
I could probably hack SQLiteCursorLoader to do this, but I wondered if there was a design reason that it doesn't at the moment? in case I get stuck in and hit a big gotcha.
I wondered if there was a design reason that it doesn't at the moment?
Sure. Those methods do the actual work in an AsyncTask, and therefore cannot return the value that you seek.
You are welcome to do your own AsyncTask to perform those operations and deal with those values, assuming that the underlying SQLite APIs support it (I don't think you can get the value you want from an update, since there are multiple rows that might be affected). You would have to call onContentChanged() on the SQLiteCursorLoader yourself, to trigger the logic to re-query the database and deliver you a fresh Cursor.
I'm sort of lost on this. I have an application that is reading from a static SQLite database that has 439397 records (~32MB).
I am querying the database on a column that is indexed, but the it takes ~8-12 seconds to finish the query. The current query I am using is to do database.query(tableName, columnHeaders, "some_id=" + id) for a list of ids.
I tried doing the "WHERE some_id IN (id1, id2, id3)" approach, but that took over twice as long. I have a feeling that I might be doing it wrong.
The query is done in an AsyncTask, so I am at a lost at what other thing I could do to improve the performance.
UPDATE:
I resolved the problem by changing the behavior of the application.
You can use EXPLAIN QUERY PLAN to confirm that your index is indeed being properly used.
You can try running your query once with a COUNT(*) instead of the real column list, to see if the issue is the act of actually reading the row data off of flash storage (which is possible if there are lots of matches and lots of big columns).
You can try running your query to match on a single ID (rather than N of them), to start to try to get a handle on whether the issue is too many comparisons.
However, please bear in mind that AsyncTask does not somehow make things magically faster. It makes things magically not run on the main application thread.
Looks like you don't have an index on that field. Note that the index might need to cover several fields if you use them for filtering/sorting/grouping in your real query (can't tell in more details because I haven't seen it).
In my Android app, I need to get 50,000 database entries (text) and compare them with a value when the activity starts (in onCreate()). I am doing this with the simplest way: I get the whole table from db to a cursor. However this way is too laggy. Are there any other ways to do it more effectively ?
Edit: The app is "scrabble solver" that is why I am not using WHERE clause in my query (Take the whole data and compare it with combination of the input letters). At first I was using a big table which contains whole possible words. Now I am using 26 tables. This reduced the lag and I am making database calls on a thread - that solved a lot problems too. It is still little bit laggy but much better.
To summarize and add a bit more
Let the database do the work of searching for you, use a WHERE clause when you perform a query!
If your where clause does not operate on the primary key column or a unique column you should create an index for that column. Here is some info on how to do that: http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html#indexes
Google says: "Use question mark parameter markers such as 'phone=?' instead of explicit values in the selection parameter, so that queries that differ only by those values will be recognized as the same for caching purposes."
Run the query analysis using EXPLAIN QUERY PLAN http://www.sqlite.org/lang_explain.html and look for any scan operations, these are much slower than search operations. Uses indexes to avoid scan operations.
Don't perform any time consuming tasks in onCreate(), always use an AsyncTask, a Handler running on a background thread or some other non-main thread.
If you need to do full text search please read: http://www.sqlite.org/fts3.html
You should never read from the database in the UI thread. Use a background thread via AsyncTask or using regular threading. This will fix the UI lag issue your having.
Making the database read faster will help with bringing the data faster to the user but it's even more important that the fetching of the data does not block the user from using the app.
Check out the Following Links:
Painless Threading in Android
YouTube: Writing Zippy Android Apps
Use a WHERE clause in your SQL rather than reading the whole thing in. Then add an index on the columns in the WHERE clause.
At least you can put index on the field you compare and use WHERE clause. If you are comparing numerics Sqlite (db engine used by Android) supports functions such as MIN and MAX. Also if you are comparing partial strings you can use LIKE. For query optimization there are many resources such as this