I just pushed a couple of changes to the master branch of couchbase-lite-ios that should help improve view indexing performance.
Indexing views together: CBL can now update multiple views’ indexes at the same time, making one pass through the updated documents in the database. That way they share the overhead of reading and parsing the docs. I did some quick benchmarking and found it was about 25% faster to index two views together vs. sequentially.
Currently, the way grouping works is that all views that share a common prefix ending in a “/“ will be indexed together. So “blog/posts” and “blog/comments” will be indexed together, and “profiles/byname” and “profiles/byid” will be indexed together, while “someview” and “otherview” will each index on their own. (This is based on the behavior of CouchDB, where views in the same ‘design document’ index together.)
A good heuristic is that views that are regularly used in the same part of your app’s UI are good to index together, because they’re likely to be queried at around the same time, so you can give them the same name prefix. By giving other views that aren’t used then a different (or no) prefix, you’ll avoid the overhead of re-indexing those when it’s not necessary.
Avoiding the overhead of emitting ‘doc’ as a value: For some reason there’s a lot of map/reduce example code out there (mostly from CouchDB) that emits the entire document (‘doc’) as the value, e.g. it does something like “emit(
doc.name, doc)”. In some cases this could speed up queries, but it really slows down indexing because of the unnecessary extra data being stored in the index. (It also slows down queries if your code isn’t going to use all the properties of the document.) The best practice is to emit only the values your query will need, or nil if you don’t need anything.
Since people unfortunately keep doing this in real apps, I’ve added a workaround to make it faster: if the emit() function sees that the value parameter is identical to the doc (by pointer comparison), it instead writes a tiny placeholder into the index. The query code recognizes this placeholder and, when you access CBLQueryRow.value, fetches the document from the database and returns its properties.
I still don’t recommend emitting the doc! You can get the same behavior by emitting nil as the value and just accessing CBLQueryRow.document instead, and it’ll probably be slightly faster. This is just a workaround for an anti-pattern that doesn’t seem to be going away. :)
As I said at the top, these changes were just checked into the master branch, so they probably won’t affect most of you for a while. I do encourage the braver among you to try them out, though, at least to see if they speed up your app. (You might need to rename some views, though.) And we’ll get these ported over to Java and C# too.
—Jens