Что такое B-дерево?

«Что такое B-дерево?» — вопрос из категории Архитектура, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

B-дерево — это сбалансированная древовидная структура данных, оптимизированная для систем, работающих с большими объемами данных, которые не помещаются в оперативную память (например, индексы в базах данных или файловые системы). Его ключевая особенность — хранение множества ключей в одном узле и большое количество потомков, что минимизирует высоту дерева и, как следствие, количество дорогостоящих операций чтения с диска (I/O).

С точки зрения тестировщика, понимание B-деревьев важно для:

  1. Проектирования тестов БД: Понимание, как устроены индексы, помогает предсказать и проверить производительность запросов (например, время выборки по индексируемому и неиндексируемому полю).
  2. Анализа планов выполнения запросов: В EXPLAIN-планах часто встречаются операции Index Scan или Index Seek, которые напрямую используют B-деревья (или их вариации, like B+ деревья).
  3. Тестирования граничных случаев: Например, проверка поведения системы при заполнении страницы индекса и её последующем разделении (split).

Основные свойства B-дерева степени t:

  • Корень содержит от 1 до 2t-1 ключей (если он не лист).
  • Каждый внутренний узел (не корень и не лист) содержит от t-1 до 2t-1 ключей.
  • Все листовые узлы находятся на одной глубине.
  • Узел с n ключами имеет n+1 потомков.

Псевдокод ключевой операции — поиска, который я бы использовал для описания логики в тест-кейсе:

def search_in_b_tree(node, key):
    i = 0
    # Находим первый ключ >= искомому
    while i < len(node.keys) and key > node.keys[i]:
        i += 1
    if i < len(node.keys) and key == node.keys[i]:
        return (node, i)  # Ключ найден в этом узле
    elif node.is_leaf:
        return None       # Ключ не найден
    else:
        # Читаем дочерний узел с диска (здесь происходит I/O операция)
        child_node = read_disk(node.children[i])
        return search_in_b_tree(child_node, key)

На практике, в СУБД (MySQL, PostgreSQL) для индексов чаще используются B+ деревья, где все ключи-значения хранятся в листьях, что ещё больше оптимизирует последовательный доступ и диапазонные запросы.