12  B-tree

Introduction

  • Assumption. So far, search trees were limited to main memory structures \to the dataset organized in a search tree fits in main memory (internal memory)
  • Problem. Transaction data of a bank > 1 TB per day \to use secondary storage media (HDD, SSD, etc.) (external memory)
  • Goal. Make a search tree structure secondary-storage-enabled

File system model

  • Page. Contiguous block of data (e.g., a file or 4,096-byte chunk).
  • Probe. First access to a page (e.g., from disk to memory).
  • Property. Time required for a probe is much larger than time to access data within a page.
  • Cost. Number of probes.
  • Goal. Access data using minimum number of probes.

B-tree

A B-tree of order M (M \geq 3) invented by Rudolf Bayer and Edward M. McCreight is an M-ary tree with the following properties:

  1. The root is either a leaf or has between 2 and M children.
  2. All nonleaf nodes (except the root) have between \left\lfloor \frac{M+1}{2}\right\rfloor and M children.
    • minimum degree m = \left\lfloor \frac{M+1}{2}\right\rfloor
    • maximum degree M
  3. All leaves are at the same depth h.
  4. All nodes store keys to guide the searching.

The height of a B-tree

If n\geq1, then for any n-key B-tree T of height h and minimum degree m, h\leq\log_{m}\frac{n+1}{2}

  • In practice. Number of probes is at most 4.
  • Optimization. Always keep root page in memory.

Structure of Node

  1. Every node x has the following fields:

    • x.n, the number of keys currently stored in node x,
    • the x.n keys themselves, x.key_{1},x.key_{2},...,x.key_{x.n} stored in nondecreasing order, so that x.key_{1}\leq x.key_{2}\leq...\leq x.key_{x.n}
    • x.leaf, a boolean value that is true if x is a leaf and false if x is an internal node.
  2. Each internal node x also contains x.n+1 pointers x.c_{1},x.c_{2},...,x.c_{x.n+1} to its children

  3. The keys x.key_{i} separate the ranges of keys stored in each subtree: if k_{i} is any key stored in the subtree with root x.c_{i}, then k_{1}\leq x.key_{1}\leq k_{2}\leq x.key_{2}\leq...\leq x.key_{x.n}\leq k_{x.n+1}

  • A simple drawing for a B-tree node

  • 2-3 tree

  • 2-3-4 tree

12.1 Basic operations on B-trees

Introduction

We adopt two conventions:

  • The root of the B-tree is always in main memory, so that a Disk-read on the root is never required; a Disk-Write of the root is required, however, whenever the root node is changed.
  • Any nodes that are passed as parameters must already have had a Disk-Read operation performed on them.

Searching

function B-Tree-Search(x, k)
    if x.leaf return null
    i ← 1
    while i ≤ x.n and k > x.key_{i}
        i ← i + 1
    if i ≤ x.n and k = x.key_{i}
        return (x, i)
    else
        Disk-Read(x.c_{i})
        return B-Tree-Search(x.c_{i}, k)
  • Challenge: Can we make any improvement?

Creating an empty B-tree

function B-Tree-Create(T)
    x ← Allocate-Node()
    x.leaf ← true
    x.n ← 0
    Disk-Write(x)
    T.root ← x

There are two kinds of algorithms:

  • “Single pass down” algorithms that proceed downward from the root of the tree, without having to back up (pre-processing)
  • “Two-pass” algorithms (post-processing)

They use three kind of actions to maintain the search tree

  • Split

  • Merge

  • Borrow (rotation)

Single-pass Insertion

Splitting a node in a B-tree

function B-Tree-Split-Child(x, i)
    z ← Allocate-Node()
    y ← x.c_{i}
    z.leaf ← y.leaf
    z.n ← m-1
    for j ← [1,...,m-1]
        z.key_{j} ← y.key_{j+m}
    if not y.leaf
        for j ← [1,...,m]
            z.c_{j} ← y.c_{j+m}
    y.n ← m-1
    for j ← [x.n+1,...,i+1]
        x.c_{j+1} ← x.c_{j}
    x.c_{i+1} ← z
    for j ← [x.n,...,i]
        x.key_{j+1} ← x.key_{j}
    x.key_{i} ← y.key_{m}
    x.n ← x.n+1
    Disk-Write(y)
    Disk-Write(z)
    Disk-Write(x)
  • B-tree(m=4,M=8): split

Inserting a key into a B-tree

function B-Tree-Insert(T, k)
    r ← T.root
    if r.n = 2m-1
        s ← Allocate-Node()
        T.root ← s
        s.leaf ← false
        s.n ← 0
        s.c_{1} ← r
        B-Tree-Split-Child(s, 1)
        B-Tree-Insert-Nonfull(s, k)
    else
        B-Tree-Insert-Nonfull(r, k)
  • B-tree(m=4,M=8): split at root

Inserting a key into a B-tree

function B-Tree-Insert-Nonfull(x, k)
    i ← x.n
    if x.leaf
        while i ≥ 1 and k < x.key_{i}
            x.key_{i+1} ← x.key_{i}
            i ← i - 1
        x.key_{i+1} ← k
        x.n ← x.n + 1
        Disk-Write(x)
    else
        while i ≥ 1 and k < x.key_{i}
            i ← i - 1
        i ← i + 1
        Disk-Read(x.c_{i})
        if x.c_{i}.n = 2m - 1
            B-Tree-Split-Child(x, i)
            if k > x.key_{i}
                i ← i + 1
        B-Tree-Insert-Nonfull(x.c_{i}, k)

Example of Insertion

Consider B-tree(m=3,M=6)

  1. Initial tree

  2. B inserted

  3. Q inserted

  4. L inserted

  5. F inserted

Insertion

Bottom-up Insertion

  1. All insertions start at a leaf node.
  2. If the node contains more than the maximum allowed number of keys, then the node is overflow:
    • A single median key is chosen from among the node’s keys
    • Keys less than the median are put in the new left node and keys greater than the median are put in the new right node.
    • The median 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.
  • B-tree(m=4,M=7)

Example of Insertion

Consider B-tree(m=2,M=3)

  1. Initial tree

  2. I inserted

  3. D inserted

Deletion

Deletion from a leaf node

  • Delete it from the node.
  • If underflow happens, rebalance the tree.

Deletion from an internal node: Each key in an internal node acts as a separation value for two subtrees

  • Choose a new separator (either the largest key in the left subtree or the smallest key in the right subtree), remove it from it is in, and replace the key to be deleted with the new separator.

Rebalancing after deletion

  1. If the deficient node’s right sibling exists and has more than the minimum number of elements, then rotate left
  2. Otherwise, if the deficient node’s left sibling exists and has more than the minimum number of elements, then
  3. 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.

Right rotation

  • B-tree(m=4,M=7)

Merge

  • B-tree(m=4,M=7)

Example of Deletion

Consider B-tree(m=2,M=3)

  1. Initial tree

  2. 24 deleted

  3. 18 deleted

12.2 Applications

Indexing

Indexing is a data structure technique to efficiently retrieve records from the database files based on some attributes on which the indexing has been done.

Indexing can be

  • Primary Index: primary key
  • Secondary Index: candidate key
  • Clustering Index: non-key

Dense Index

  • In dense index, there is an index record for every search key value in the database. This makes searching faster but requires more space to store index records itself. Index records contain search key value and a pointer to the actual record on the disk.

Sparse Index

  • In sparse index, index records are not created for every search key.

Multilevel Index

  • Multi-level Index helps in breaking down the index into several smaller indices in order to make the top level so small that it can be saved in a single disk block, which can easily be accommodated anywhere in the main memory.

B-tree variants

B-tree variants

B+ tree is a 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.

B* tree is a B-tree that ensures non-root nodes are at least 2/3 full instead of 1/2.

Searching a B+ Tree

Table people

ID name age
1 Peter 20
2 Mary 30
3 John 25

Queries

SELECT name
FROM people
WHERE age = 25

Exact key values:

  • Start at the root
  • Proceed down, to the leaf
SELECT name
FROM people
WHERE 20 <= age AND age <= 30 

Range queries:

  • As above
  • Then sequential traversal

Applications

B-trees (and variants) are widely used for file systems and databases.

  • Windows: NTFS.
  • Mac: HFS, HFS+.
  • Linux: ReiserFS, XFS, Ext3FS, JFS.
  • Databases: ORACLE, DB2, INGRES, SQL, PostgreSQL.

12.3 Workshop

Quiz

  1. What is a B-tree?
  2. What is Indexing?

Projects

12.4 References