How b-tree database indexes work and how to tell if they are efficient
mattfleming.com
mattfleming.com
If so, why would database implementations make this tradeoff?
Two advantages I can think of: a b-tree offers very quick sorting (because data is already sorted). It is probably more efficient to grow a b-tree in place on disk without having to move too much data around too often.
While these two things matter, O(log(n)) vs. O(1) read performance is a big difference. And if I'm not mistaken, most databases ought to be read optimized to begin with.
Can someone enlighten me on the implementation considerations here?
Mainly, though, each b+-tree node is the same size as a disk I/O block. The disk is often the slowest part of the database, so making as few reads as possible will go a long way. If you can't work entirely in memory, that's the next best thing.
That makes no sense. An external hash index is also designed to do as few I/Os per read as well (typically just a single I/O to read the page that holds the target bucket). Just like b-trees are designed differently than in-memory trees, external hash indexes are designed differently than in-memory hash tables.
Another problem with hash tables is that if your keys are large (varchars), you have to hash the entire string, or deal with more collisions. A reasonable balanced tree index on varchars just needs to call strncmp(3), which can terminate much sooner than a hash function. Of course, it's unlikely that your index, if it's large enough for you to care, is going to be CPU-bound, but it's important to remember that the constant inside the O(1) (amortized) hash table is probably going to be pretty large in this case.
Not necessarily true; linear hashing avoids this requirement, for example. http://en.wikipedia.org/wiki/Linear_hashing
Not only can a b-tree locate the edges of such a range, but if you're accessing k rows from an n-row table, your index access time is O(k + log(n)) with k quickly becoming the dominant factor.
Even when you're accessing one row per query, these queries will often be favouring a particular cluster of row, rather than being perfectly evenly distributed over the table. In such cases a b-tree will provide better locality of reference; you'll hit cached data in memory rather than disk far more often.
Neither of those claims is true. A hash index is perfectly useful for queries that return multiple rows: the index just stores all the duplicate values for the search predicate in the matching hash bucket. And hash indexes can certainly be used with aggregate functions: you first use the hash index to evaluate the query predicate (WHERE clause), and then you evaluate the aggregation or grouping clause over the results of the hash index.
Your counterexamples are true where all the returned/aggregated rows have the same indexed value; it may make sense to hash index under such circumstances, but b-trees are a more sensible default.
I guess you could also have a situation where a range predicate maps nicely to a proportionate number of hash buckets. I don't know if any databases are clever enough to do this.
1. You need to know roughly how many rows the table will have, and the row size at table creation time. 2. Oracle will allocate all that space at creation time, and so a full table scan will take a long time.
So long as you know the deal with them, hash cluster tables can prove very efficient for the correct problem.
That's probably on the high side. Suppose that records are stored in 8KB pages (which is probably too small for a modern system, but nevermind), the selectivity of the scan is 10%, the records that satisfy the scan are randomly distributed over the pages, each page holds, say, 40 records (which is conservative, even for small 8KB pages), and we're considering scanning a secondary index[1].
That means that a typical page in the heap has 4 matching records, which means we are very likely to have to read every page in the heap anyway. Worst still, the order in which the index scan returns results is unlikely to correlate with the physical storage order of the heap pages, which means that the 4 IOs per page are going to be random, not sequential. Add to that, in a scan of a secondary index, you need to read both the index page and the pointed-to heap page, which is an additional I/O (compared to a sequential scan of the heap). So it's easy to construct a realistic scenario when you wouldn't want to use a secondary index when the scan selectivity is "only" 10%.
[1] And that an index-only plan can't be used: i.e. we need to fetch the pointed-to heap page.
1. Create a multi-column index that satisfies the query entirely on its own without the need to go to the table to read additional data. This technique solves a large percentage of slow query problems.
2. A bitmap index in Oracle kills concurrency. Do not use bitmap indexes for table with multiple concurrent transactions.
create fbi on table(case
when skewed_col == 'small value'
skewed_col
else
null
end)
The null values are never indexed, so now you have a nice small index that is good only for finding you 'needles in the haystack', so long as you put that case statement in your queries.