MongoDB, count() and the big O
coffeepowered.net
coffeepowered.net
My solution ultimately ended up being to put the leaderboards that are doing that particular thing into a special "truncate" list that periodically deletes everything after their 50,000th score.
http://openmymind.net/2011/5/8/Practical-NoSQL-Solving-a-Rea...
Understandably this is the cost of using things like mongodb. Until now I've been very happy with the benefits and tradeoffs but the problems with count() for reasonably sized collections was a particularly nasty surprise.
All in all, it's something of a sore spot in an otherwise very enjoyable development experience.
This would be much easier to do if Mongo had triggers.
I added a class method for Mongoid::Documents called limit_max_count_results_to that limits the size of Kaminari's total_count
I think the right map reduce view in Couch is good for count.
But after studying data structures, I realized that most other databases have a lot of time complexity involved that they are basically sweeping under the rug, whereas Couch's relatively simple query model can guarantee that it's roughly O(log(M) + N).
(That said, an index doesn't make this magically faster... the fast performance that people credit MyISAM with is that asking for the total number of rows in a table was O(1), as its lack of intricate transaction concurrency allowed it to just keep a global counter; one which of course was difficult and costly to repair after an unclean outage. In comparison, that indexes can optimize a count() over a where is obvious and true of any sane database engine, whether it be PostgreSQL or any of the common MySQL backends.)
MySQL can do index only queries, whereas PG currently can not (it is part of the next release iirc). This can often result in a fraction of the disk I/O being done for MySQL.
Thanks for pointing this out, though! I'm going to go look into how InnoDB manages to handle that.
WHERE id > 0
For some reason counting with that is a lot faster (from my testing) to just a straight count
Questions:
1) What version of MySQL are you testing on?
2) What storage engine are the relevant tables using?
3) What does the execution plan show for both cases (with where id > 0 and w/out it)?
[1] select count(object_id) from wp_term_relationships force index(PRIMARY);
[2] select count([asterisk]) from wp_term_relationships
[3] select count([asterisk]) from wp_posts
... all of which produce execution plans that show indexes are being used to perform the count() query. All tables are using InnoDB.
Off topic question: how do you escape an asterisk when entering a reply so that it shows w/in the thread vs. italicizing text?
This stuff is hard. Nothing comes for free. I don't even use mongodb in any production project and am really feeling for them. All these pseudo functional developers think they know how things should work and then get all indignant when stuff doesn't work the way they want it to or think it should.
In this season of Thanks, let us give thanks to the real engineers who make these databases (and other software) and then give them out to everyone for free. Go send a polite email to their mailing lists and say "Dear OpenSource Developer, Thank you for all your hard work."
Re. this specific problem - cache your data and stop crying about it or simply don't present counts to users.
The impetus for this particular post was that it was somewhat surprising that counts were still doing full scans, even if the query conditions were on an indexed field. My expectation was that the index might have some information on how big a particular part of the index tree is (given two bounds), but it turns out that it doesn't, so you end up looking at each document and doing inspection per row. This isn't normally a problem, but the comparison is relatively slow, so the whole thing starts to drag down faster than you'd normally expect.
When the problem is hidden below several levels of library/ORM candy coating, it's not going to be immediately obvious that this is a problem, especially if the queries against that field are otherwise performant thanks to proper use of indexes. It's non-obvious, and given that someone else found it interesting enough to post here, I'm apparently not the only person in the world to ever have this problem. There are multiple open tickets in the Mongo JIRA system, as well as multiple discussions on this topic on the mailing list. This isn't me whining that 10gen won't fix my software, it's an acknowledgment of the problem and steps towards fixing it.
10gen themselves have acknowledged via the mailing lists that counts are slower than they should be, and it's on the list of things to improve. Until then, we have to make do with workarounds.
@cheald, clearly this isn't your fault, and you don't control the tenor of the discussion of mongoDB. What follows isn't a criticism of you, but more a general comment.
I don't think that criticism of mongoDB should be stifled on HN (it clearly still has huge flaws--the lack of granularity when grabbing the write lock comes to mind), but it seems like it's a little hard to have an intelligent conversation in this context. It might make sense to encourage HN to discuss mongo in a way that it's not criticizing a performance detail (no database can do everything for everyone), eg where it can be compared against other databases. When criticizing a performance detail, it might make sense to move that discussion to the MongoDB Jira, where your voice can actually help influence decision making.