My app needs to get synced with other app users (on there own devices). I also want to support offline editing, that are synchronized to the other collaborative users when the user gets connected to the internet.
So the User A changes (while he is offline) some data (in ohter words he would update database entries) or add new records to the database. When User A gets connected to the internet, all changes and new records are delivered to the other collaborative Users. So User B will get the changes/updates and can insert/update them into User Bs local device database.
But I need to ensure that the ids of the database entries are unique along the whole system. Therefore I need to use something like UUID.
My question: Is it a bad idea to use a UUID (String / Varchar) as primary key in a android sqlite database table instead of an integer that would be auto incremented?
I guess there would be performance issues by using strings (a UUID has 36 characters) as primary key.
I guess indexing uuids instead of integers takes longer (comparing string vs. comparing integers). I also guess that when Im using UUID, every time a new database record/entry has been inserted the database needs to reindex the primary key column, since they primary key index is not in a sorted order anymore (which would be when I would use integer auto increment primary key, because every future record is added at the end, because the new auto incremented primary key is always the greatest number so far, so the index will automatically be in sorted order). What i also need to do is JOINS over 2 - 3 tables. I also guess that comparing strings on JOINS instead of integer would slow down the database query.
However I cant see any other possibility to implement such a collaborative syncing system, so I must use UUID, right?
Another possibility would be to use a integer auto increment primary key and to use a second column uuid. So to work on the users local device, i would use this primary key (integer) for JOINS etc., while I would use the uuid column for syncing with the other users.
What do you guys think about that approach or is it in your opinion to much work, since you wont expect a big significant performance issue by ussing UUID directly as primary key?
Any other suggestions?
Is it a bad idea to use a UUID (String / Varchar) as primary key in a android sqlite database table instead of an integer that would be auto incremented?
The only for-certain problem that I can think of is that you will not be able to use CursorAdapter and its subclasses for displaying the results of queries on that table. CursorAdapter requires a unique integer _id column in the Cursor, and presumably you will not have one of those. You would have to create your own adapter, perhaps extending BaseAdapter, that handles it.
I guess there would be performance issues by using strings (a UUID has 36 characters) as primary key.
Possibly, but I will be somewhat surprised if it turns into a material problem on device-sized databases.
However I cant see any other possibility to implement such a collaborative syncing system, so I must use UUID, right?
You need some sort of UUID for your network protocol. Presumably, you will need that UUID in your database. Whether that UUID needs to be the primary key of a table, I can't say, because I don't know your schema.
Another possibility would be to use a integer auto increment primary key and to use a second column uuid. So to work on the users local device, i would use this primary key (integer) for JOINS etc., while I would use the uuid column for syncing with the other users.
Correct. You would have a UUID->local integer ID mapping table, use the UUIDs in your network protocol, and keep the local database mostly using the local integer IDs. Whether or not this will be a significant performance improvement (particularly given the increased database schema complexity), I can't say.
What do you guys think about that approach or is it in your opinion to much work, since you wont expect a big significant performance issue by ussing UUID directly as primary key?
IMHO, either run some performance tests so you get some concrete comparable data, or only worry about it if your database I/O seems sluggish.
One set of performance results for UUIDs as binary and text can be found in somewhat related UUID/SQLite question: https://stackoverflow.com/a/11337522/3103448
Per the results, both binary and string UUIDs can be efficient in SQLite for Create and Query when indexed. A separate trade-off is whether a human readable string is preferred to the smaller data size of binary file size.
Related
Not sure if this has already been answered, and this is kind of a dumb question, but I'm kinda new to using SQL in android and I've made a simple task app using the language. In the app, I added a feature to delete all tasks. When I create a new one, the primary key keeps counting up. Now, there's nothing wrong with the app or the code or anything, but if all the tasks are deleted, should I reset the primary key, or is it bad practice to do so? If not, will it ever become large enough to provoke a crash?
I would generally keep it increment because it can simplify certain things like database backup/restores, and replication to other database nodes. It makes things more predictable when your rows are always unique by id.
From the SQLite documentation:
Except for WITHOUT ROWID tables, all rows within SQLite tables have a 64-bit signed integer key that uniquely identifies the row within its table.
How big is the largest 64 bit number? It is 9,223,372,036,854,775,807. This number is so large, that it is probably doubtful you will ever exceed it, unless you are doing very frequent and massive inserts. Actually, you might run out of storage space before you insert so many rows to even come close to this number.
I have a bit of a theoretical question for which there is no code yet as I am still just in the thinking stage. I want to update an app to allow users to share their data with others through DropBox Datastore or something like that. However, when a user creates data which get populated into multiple sqlite tables on the device, each table has an auto-incremental integer as a primary key that is used as a foreign key in other tables to link the data.
If there is more than one user actually creating the data and sharing it then the primary key columns are obviously going to be an issue. If I download the data and store it locally I obviously can't insert user 1's key value in user 2's data table, firstly because of the auto-increment and secondly because user 2 might already have data that is not shared saved with that key value.
I have thought about a few options but nothing is particularly appealing or robust. I was thinking about creating a UUID to identify the device, that value would have to be stored in each of the tables and the primary key would be a combination of that column and the current primary key integer which would obviously have to have the auto-increment removed. So to pick up all related data from each table the id column and UUID column would both have to be used.
I feel like there must be a more robust method of achieving this though, any one have any better suggestions?
If I'm understanding well you need some sort centralised database in the cloud to communicate with your local app, is that right?
A client should never create the ids for such a system. A usual practice on these cases is to always have a remote id which is created by your DB in the cloud, and whenever you don't have this value yet, you can have a fallback value (local id created locally - which is different from the remote one).
So, to illustrate my words we could set the following example. Your app stores messages in database. Say you create messages with a local id 1,2,3. Those ids will never be meant to be unique in your central database in the cloud. Instead, you'd just use them as a local fallback. As soon as you can send those 3 messages to your centralised database, it'll give them 3 new remote ids you'll use for unique means (ie.: 35, 46, 54).
Note that when you have multiple requesters/users accessing one same database there's not such way to assure uniqueness unless you follow the explained approach, or you query a certain number of unique ids in advance and on demand to your database in the cloud.
Keep in mind, that the actual truth can be only delivered by the databases in your servers.
I have a sqlite database on a multi device android system that requires UUID (yes it requires them), however I do not set the UUID as the primary key, instead the UUID is just a column and the primary key is just an INTEGER on each device (that is not transferred) but instead auto generated on the local android database
I am doing an Update (if failed) insert routine based on if the UUID exists -which is quite slow and eventually I want to convert this into a bulk system with the SQLITESTATEMENT
however in order for me to get to that point I need to make the INSERT OR REPLACE (or REPLACE INTO) work with my data set - From what I understand it only works based on if the primary key already exists - since my primary key is not what I actually care about how do I make the Replace Into work based of a different column?
Or perhaps I can do bulk inserts a different way - that does not involve replace intos - but can still handle inserts or updates -
any help is appreciated
Some of the items I have been using for references
How do I UPDATE a row in a table or INSERT it if it doesn't exist?
http://www.buzzingandroid.com/2013/01/sqlite-insert-or-replace-through-contentprovider/
Improve INSERT-per-second performance of SQLite?
How do I use prepared statements in SQlite in Android?
http://developer.android.com/reference/android/database/sqlite/SQLiteStatement.html#execute()
Android SQLite database: slow insertion
You can use INSERT OR REPLACE even if the UUID is not the primary key as long as you make the UUID field UNIQUE;
CREATE TABLE test (
id INTEGER PRIMARY KEY AUTOINCREMENT,
uuid UUID UNIQUE NOT NULL
);
Any insert that violates the UNIQUE constraint replaces the existing row (but generates a new primary key for the new row)
A very simple SQLfiddle to test with.
I'm using Virgil Dobjanschi's Option B (from this talk: http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html) to implement a web service on my Android App to connect to a Google Cloud Endpoints RESTful service (hence, my URLs are abstracted over).
The local SQLite database requires a Primary key (which must be called _id so it can link with a ListView). The AppEngine service also requires a unique ID per record. The resources in the service are shared between multiple clients, so their IDs need to be maintained unique on the server. The resource ID is generated, derived from two other IDs, and in the form of a String.
By design, these resources are never created locally on the Android app, they are only read and updated - creation and deletion happens elsewhere, and then those created are sent via Google Cloud Messaging, complete with their REST Ids, and inserted into the SQLite table.
If I ever do create them locally, I'll be able to generate the unique ID from the REST resource locally as well.
Should I have the ID on the SQLite database be a separate unique id, maintained locally, and store the REST id in the record, or should I set the SQLite ID to be the same as the REST id?
ie:
My REST Resources are of the form:
String id; // unique, derived from two other ids
String data;
My SQLite options are:
create table myResource (
_id INTEGER PRIMARY KEY AUTOINCREMEMT,
restId TEXT,
data TEXT);
Or:
create table myResource (
_id TEXT PRIMARY KEY,
data TEXT);
In the first option, I could make restId UNIQUE as well. I'm leaning towards the second option, but am wondering if I'll run into unforeseen problems with this approach.
I also have another similar situation with some different resources where the REST key is a Long rather than a String, but I still question whether I should maintain a local primary key separate to the REST resource ID.
It seems that it's best to use Integers for the _id field in SQLite, which means that they necessarily won't match the String Keys in AppEngine.
The http://developer.android.com/reference/android/content/ContentUris.html refers to id as "A unique numeric identifier", and provides helper methods that require it to be a long.
It may be possible to work around this, but given that this assumption is built in to ContentUris, I expect that it will also be built in elsewhere, so it would be easier to do this with numeric ids kept internal to the App, and enforce uniqueness of the AppEngine keys separately.
The example apps and documentation I've seen so far seems to use Parse as the primary (if not only) storage solution for the app, which is great in some situations.
I'm looking to integrate Parse with an existing application of mine on Android, which uses multiple SQLite tables in a single database.
Are there any examples which show usage of Parse, where local storage (i.e. the SQLite DBs) is the primary storage, and data is only sync'd between Parse and local storage if there are newer changes which need updating/committing?
For my database, I have two tables, Tasks and Dates. Tasks is formed of:
_id (a unique integer key for this table)
item (a String describing the task)
desc (a String with a longer description - may be null)
parent (an integer indicating the _id of this task's parent)
and Date:
_id (a unique integer key for this table)
item_id (a foreign key which corresponds to _id in Tasks) date (a date stored in long
format)
In this instance, would I store each row as a separate ParseObject? Having different classes for Task and Date, and I could link Dates with their Task parents? Is this the recommended way?
--
Edit: I received a reply from an engineer at Parse who said that it's possible (to sync with a local SQLite DB), but that it's not supported, and didn't comment on the method I proposed - specifically mapping rows to ParseObjects.
I have been thinking on similar lines but there is not adapter or library that implements the sync. So, you would have to implement it from scratch. Seeing as your schema is pretty straight-forward, it shouldn't be too difficult.
Is the solution is appropriate: in your scenario parse.com would act as any other REST service that would provide data, so I don't see any problems.
Actually, now there is a simple library for Parse <=> sqlite integration.
Check out https://github.com/ntoskrnl/DataSync