Origin
B-trees were invented by Rudolf Bayer andDefinition
According to Knuth's definition, a B-tree of order ''m'' is a tree which satisfies the following properties: # Every node has at most ''m'' children. # Every internal node has at least ⌈''m''/2⌉ children. # Every non-leaf node has at least two children. # All leaves appear on the same level. # A non-leaf node with ''k'' children contains ''k''−1 keys. Each internal node's keys act as separation values which divide its subtrees. For example, if an internal node has 3 child nodes (or subtrees) then it must have 2 keys: ''a''1 and ''a''2. All values in the leftmost subtree will be less than ''a''1, all values in the middle subtree will be between ''a''1 and ''a''2, and all values in the rightmost subtree will be greater than ''a''2. ;Internal nodes : Internal nodes (also known as inner nodes) are all nodes except for leaf nodes and the root node. They are usually represented as an ordered set of elements and child pointers. Every internal node contains a maximum of ''U'' children and a minimum of ''L'' children. Thus, the number of elements is always 1 less than the number of child pointers (the number of elements is between ''L''−1 and ''U''−1). ''U'' must be either 2''L'' or 2''L''−1; therefore each internal node is at least half full. The relationship between ''U'' and ''L'' implies that two half-full nodes can be joined to make a legal node, and one full node can be split into two legal nodes (if there's room to push one element up into the parent). These properties make it possible to delete and insert new values into a B-tree and adjust the tree to preserve the B-tree properties. ;The root node : The root node's number of children has the same upper limit as internal nodes, but has no lower limit. For example, when there are fewer than ''L''−1 elements in the entire tree, the root will be the only node in the tree with no children at all. ;Leaf nodes : In Knuth's terminology, the "leaf" nodes are the actual data objects / chunks. The internal nodes that are one level above these leaves are what would be called the "leaves" by other authors: these nodes only store keys (at most ''m''-1, and at least ''m''/2-1 if they are not the root) and pointers (one for each key) to nodes carrying the data objects / chunks. A B-tree of depth ''n''+1 can hold about ''U'' times as many items as a B-tree of depth ''n'', but the cost of search, insert, and delete operations grows with the depth of the tree. As with any balanced tree, the cost grows much more slowly than the number of elements. Some balanced trees store values only at leaf nodes, and use different kinds of nodes for leaf nodes and internal nodes. B-trees keep values in every node in the tree except leaf nodes.Differences in terminology
The literature on B-trees is not uniform in its terminology. Bayer and McCreight (1972), Comer (1979), and others define the order of B-tree as the minimum number of keys in a non-root node. points out that terminology is ambiguous because the maximum number of keys is not clear. An order 3 B-tree might hold a maximum of 6 keys or a maximum of 7 keys. Knuth (1998) avoids the problem by defining the order to be the maximum number of children (which is one more than the maximum number of keys). The term leaf is also inconsistent. Bayer and McCreight (1972) considered the leaf level to be the lowest level of keys, but Knuth considered the leaf level to be one level below the lowest keys. There are many possible implementation choices. In some designs, the leaves may hold the entire data record; in other designs, the leaves may only hold pointers to the data record. Those choices are not fundamental to the idea of a B-tree. For simplicity, most authors assume there are a fixed number of keys that fit in a node. The basic assumption is the key size is fixed and the node size is fixed. In practice, variable length keys may be employed.Informal description
Variants
The term B-tree may refer to a specific design or it may refer to a general class of designs. In the narrow sense, a B-tree stores keys in its internal nodes but need not store those keys in the records at the leaves. The general class includes variations such as the B+ tree, the B* tree and the B*+ tree. * In the B+ tree, copies of the keys are stored in the internal nodes; the keys and records are stored in leaves; in addition, a leaf node may include a pointer to the next leaf node to speed sequential access. * The B* tree balances more neighboring internal nodes to keep the internal nodes more densely packed. This variant ensures non-root nodes are at least 2/3 full instead of 1/2. As the most costly part of operation of inserting the node in B-tree is splitting the node, B*-trees are created to postpone splitting operation as long as they can. To maintain this, instead of immediately splitting up a node when it gets full, its keys are shared with a node next to it. This spill operation is less costly to do than split, because it requires only shifting the keys between existing nodes, not allocating memory for a new one. For inserting, first it is checked whether the node has some free space in it, and if so, the new key is just inserted in the node. However, if the node is full (it has keys, where is the order of the tree as maximum number of pointers to subtrees from one node), it needs to be checked whether the right sibling exists and has some free space. If the right sibling has keys, then keys are redistributed between the two sibling nodes as evenly as possible. For this purpose, keys from the current node, the new key inserted, one key from the parent node and keys from the sibling node are seen as an ordered array of keys. The array becomes split by half, so that lowest keys stay in the current node, the next (middle) key is inserted in the parent and the rest go to the right sibling. (The newly inserted key might end up in any of the three places.) The situation when right sibling is full, and left isn't is analogous. When both the sibling nodes are full, then the two nodes (current node and a sibling) are split into three and one more key is shifted up the tree, to the parent node. If the parent is full, then spill/split operation propagates towards the root node. Deleting nodes is somewhat more complex than inserting however. * The B*+ tree combines the main B+ tree and B* tree features together. * B-trees can be turned into order statistic trees to allow rapid searches for the Nth record in key order, or counting the number of records between any two records, and various other related operations.B-tree usage in databases
Time to search a sorted file
Usually, sorting and searching algorithms have been characterized by the number of comparison operations that must be performed using order notation. A binary search of a sorted table with records, for example, can be done in roughly comparisons. If the table had 1,000,000 records, then a specific record could be located with at most 20 comparisons: . Large databases have historically been kept on disk drives. The time to read a record on a disk drive far exceeds the time needed to compare keys once the record is available. The time to read a record from a disk drive involves aAn index speeds the search
A B-tree index creates a multi-level tree structure that breaks a database down into fixed-size blocks or pages. Each level of this tree can be used to link those pages via an address location, allowing one page (known as a node, or internal page) to refer to another with leaf pages at the lowest level. One page is typically the starting point of the tree, or the "root". This is where the search for a particular key would begin, traversing a path that terminates in a leaf. Most pages in this structure will be leaf pages which ultimately refer to specific table rows. A significant improvement in performance can be made with a B-treeInsertions and deletions
If theAdvantages of B-tree usage for databases
The B-tree uses all of the ideas described above. In particular, a B-tree: * keeps keys in sorted order for sequential traversing * uses a hierarchical index to minimize the number of disk reads * uses partially full blocks to speed up insertions and deletions * keeps the index balanced with a recursive algorithm In addition, a B-tree minimizes waste by making sure the interior nodes are at least half full. A B-tree can handle an arbitrary number of insertions and deletions.Best case and worst case heights
Let be the height of the classic B-tree (see for the tree height definition). Let be the number of entries in the tree. Let ''m'' be the maximum number of children a node can have. Each node can have at most keys. It can be shown (by induction for example) that a B-tree of height ''h'' with all its nodes completely filled has entries. Hence, the best case height (i.e. the minimum height) of a B-tree is: : Let be the minimum number of children an internal (non-root) node must have. For an ordinary B-tree, Comer (1979) and Cormen et al. (2001) give the worst case height (the maximum height) of a B-tree as :Algorithms
Search
Searching is similar to searching a binary search tree. Starting at the root, the tree is recursively traversed from top to bottom. At each level, the search reduces its field of view to the child pointer (subtree) whose range includes the search value. A subtree's range is defined by the values, or keys, contained in its parent node. These limiting values are also known as separation values. Binary search is typically (but not necessarily) used within nodes to find the separation values and child tree of interest.Insertion
All insertions start at a leaf node. To insert a new element, search the tree to find the leaf node where the new element should be added. Insert the new element into that node with the following steps: # If the node contains fewer than the maximum allowed number of elements, then there is room for the new element. Insert the new element in the node, keeping the node's elements ordered. # Otherwise the node is full, evenly split it into two nodes so: ## A single median is chosen from among the leaf's elements and the new element that is being inserted. ## Values less than the median are put in the new left node and values greater than the median are put in the new right node, with the median acting as a separation value. ## The separation value is inserted in the node's parent, which may cause it to be split, and so on. If the node has no parent (i.e., the node was the root), create a new root above this node (increasing the height of the tree). If the splitting goes all the way up to the root, it creates a new root with a single separator value and two children, which is why the lower bound on the size of internal nodes does not apply to the root. The maximum number of elements per node is ''U''−1. When a node is split, one element moves to the parent, but one element is added. So, it must be possible to divide the maximum number ''U''−1 of elements into two legal nodes. If this number is odd, then ''U''=2''L'' and one of the new nodes contains (''U''−2)/2 = ''L''−1 elements, and hence is a legal node, and the other contains one more element, and hence it is legal too. If ''U''−1 is even, then ''U''=2''L''−1, so there are 2''L''−2 elements in the node. Half of this number is ''L''−1, which is the minimum number of elements allowed per node. An alternative algorithm supports a single pass down the tree from the root to the node where the insertion will take place, splitting any full nodes encountered on the way preemptively. This prevents the need to recall the parent nodes into memory, which may be expensive if the nodes are on secondary storage. However, to use this algorithm, we must be able to send one element to the parent and split the remaining ''U''−2 elements into two legal nodes, without adding a new element. This requires ''U'' = 2''L'' rather than ''U'' = 2''L''−1, which accounts for why some textbooks impose this requirement in defining B-trees.Deletion
There are two popular strategies for deletion from a B-tree. # Locate and delete the item, then restructure the tree to retain its invariants, OR # Do a single pass down the tree, but before entering (visiting) a node, restructure the tree so that once the key to be deleted is encountered, it can be deleted without triggering the need for any further restructuring The algorithm below uses the former strategy. There are two special cases to consider when deleting an element: # The element in an internal node is a separator for its child nodes # Deleting an element may put its node under the minimum number of elements and children The procedures for these cases are in order below.Deletion from a leaf node
# Search for the value to delete. # If the value is in a leaf node, simply delete it from the node. # If underflow happens, rebalance the tree as described in section "Rebalancing after deletion" below.Deletion from an internal node
Each element in an internal node acts as a separation value for two subtrees, therefore we need to find a replacement for separation. Note that the largest element in the left subtree is still less than the separator. Likewise, the smallest element in the right subtree is still greater than the separator. Both of those elements are in leaf nodes, and either one can be the new separator for the two subtrees. Algorithmically described below: # Choose a new separator (either the largest element in the left subtree or the smallest element in the right subtree), remove it from the leaf node it is in, and replace the element to be deleted with the new separator. # The previous step deleted an element (the new separator) from a leaf node. If that leaf node is now deficient (has fewer than the required number of nodes), then rebalance the tree starting from the leaf node.Rebalancing after deletion
Rebalancing starts from a leaf and proceeds toward the root until the tree is balanced. If deleting an element from a node has brought it under the minimum size, then some elements must be redistributed to bring all nodes up to the minimum. Usually, the redistribution involves moving an element from a sibling node that has more than the minimum number of nodes. That redistribution operation is called a rotation. If no sibling can spare an element, then the deficient node must be merged with a sibling. The merge causes the parent to lose a separator element, so the parent may become deficient and need rebalancing. The merging and rebalancing may continue all the way to the root. Since the minimum element count doesn't apply to the root, making the root be the only deficient node is not a problem. The algorithm to rebalance the tree is as follows: * If the deficient node's right sibling exists and has more than the minimum number of elements, then rotate left *# Copy the separator from the parent to the end of the deficient node (the separator moves down; the deficient node now has the minimum number of elements) *# Replace the separator in the parent with the first element of the right sibling (right sibling loses one node but still has at least the minimum number of elements) *# The tree is now balanced * Otherwise, if the deficient node's left sibling exists and has more than the minimum number of elements, then rotate right *# Copy the separator from the parent to the start of the deficient node (the separator moves down; deficient node now has the minimum number of elements) *# Replace the separator in the parent with the last element of the left sibling (left sibling loses one node but still has at least the minimum number of elements) *# The tree is now balanced * Otherwise, if both immediate siblings have only the minimum number of elements, then merge with a sibling sandwiching their separator taken off from their parent *# Copy the separator to the end of the left node (the left node may be the deficient node or it may be the sibling with the minimum number of elements) *# Move all elements from the right node to the left node (the left node now has the maximum number of elements, and the right node – empty) *# Remove the separator from the parent along with its empty right child (the parent loses an element) *#* If the parent is the root and now has no elements, then free it and make the merged node the new root (tree becomes shallower) *#* Otherwise, if the parent has fewer than the required number of elements, then rebalance the parent :Note: The rebalancing operations are different for B+ trees (e.g., rotation is different because parent has copy of the key) and B*-tree (e.g., three siblings are merged into two siblings).Sequential access
While freshly loaded databases tend to have good sequential behavior, this behavior becomes increasingly difficult to maintain as a database grows, resulting in more random I/O and performance challenges.Initial construction
A common special case is adding a large amount of ''pre-sorted'' data into an initially empty B-tree. While it is quite possible to simply perform a series of successive inserts, inserting sorted data results in a tree composed almost entirely of half-full nodes. Instead, a special "bulk loading" algorithm can be used to produce a more efficient tree with a higher branching factor. When the input is sorted, all insertions are at the rightmost edge of the tree, and in particular any time a node is split, we are guaranteed that no more insertions will take place in the left half. When bulk loading, we take advantage of this, and instead of splitting overfull nodes evenly, split them as ''unevenly'' as possible: leave the left node completely full and create a right node with zero keys and one child (in violation of the usual B-tree rules). At the end of bulk loading, the tree is composed almost entirely of completely full nodes; only the rightmost node on each level may be less than full. Because those nodes may also be less than ''half'' full, to re-establish the normal B-tree rules, combine such nodes with their (guaranteed full) left siblings and divide the keys to produce two nodes at least half full. The only node which lacks a full left sibling is the root, which is permitted to be less than half full.In filesystems
In addition to its use in databases, the B-tree (or ) is also used in filesystems to allow quick random access to an arbitrary block in a particular file. The basic problem is turning the file block address into a disk block (or perhaps to aPerformance
A B-tree grows slower with growing data amount, than the linearity of a linked list. Compared to aVariations
Access concurrency
Lehman and Yao showed that all the read locks could be avoided (and thus concurrent access greatly improved) by linking the tree blocks at each level together with a "next" pointer. This results in a tree structure where both insertion and search operations descend from the root to the leaf. Write locks are only required as a tree block is modified. This maximizes access concurrency by multiple users, an important consideration for databases and/or other B-tree-based ISAM storage methods. The cost associated with this improvement is that empty pages cannot be removed from the btree during normal operations. (However, see for various strategies to implement node merging, and source code at.) United States Patent 5283894, granted in 1994, appears to show a way to use a 'Meta Access Method' to allow concurrent B+ tree access and modification without locks. The technique accesses the tree 'upwards' for both searches and updates by means of additional in-memory indexes that point at the blocks in each level in the block cache. No reorganization for deletes is needed and there are no 'next' pointers in each block as in Lehman and Yao.Parallel algorithms
Since B-trees are similar in structure toSee also
* B+ tree * R-tree * Red–black tree *Notes
References
;General * * . * . Chapter 18: B-Trees. * * . Section 6.2.4: Multiway Trees, pp. 481–491. Also, pp. 476–477 of section 6.2.3 (Balanced Trees) discusses 2–3 trees.Original papers
* . * .External links