Constant factors: constantly foiling you
blog.ksplice.com
blog.ksplice.com
OP is benchmarking two instances of COUNTs against a relational database, each looking for the total number of rows in a 3 day period, right?
I'm going to make a guess that this is historical data and that "time" is stamped and never changes again...
Why not just pre-answer the question by incrementing a field (based on date) in another table every time you add a record. Then instead of COUNTing millions of records in seconds, you can read 3 records in micro-seconds.
I know what you're thinking: this will "slow down" your transaction processing time. That's true, but only by microseconds. I'd rather wait a few microseconds several times per day than 61 seconds when I really needed to know something.
Just because a DBMS has lots of capabilities (SQL, indexing, triggers, stored procedures) doesn't necessarily mean that's the best way to deploy something. Sometimes a little thinking and some extra functionality in your app can leapfrog mountains.
[Aside: I have implemented this exact solution many times, often reducing historical reporting run times by 95% or more. No one ever noticed any latency at transaction update time.]
Your idea is a good one for when the count is what's needed, though. Even in more complex cases, maintaining aggregate data ready to go can help a lot.
Since b-trees have the guarantee that no root-to-leaf path is more than a constant factor longer than any other, you are probably hitting the very edge of that constant, and since disk seeks are the designated hitter of the performance team, you're getting hit pretty hard.
So, effectively, even your index is growing fragmented the more you use it.
To verify the fact that you're not hitting the data file though, maybe you could strace it and watch for reads on the index and the data file.
You're definitely right that the cache should be hot though, so I am now also a skeptical hue.
You could cluster the table on the 'time' column. That would store the data in the table in the same order as it appears in the index, and make time-based range queries a lot faster.