Как выглядит индекс B-дерева более чем на 1 столбец?
Итак, я читал об индексах и их реализации, и я наткнулся на этот сайт, который содержит краткое объяснение индексов b-tree:
http://20bits.com/articles/interview-questions-database-indexes/
Индекс b-дерева имеет смысл для индексов, которые находятся только в одном столбце, но пусть я создаю индекс с несколькими столбцами, как тогда работает b-дерево? Какова ценность каждого node в b-дереве?
Например, если у меня есть эта таблица:
table customer:
id number
name varchar
phone_number varchar
city varchar
и я создаю индекс на: (id, name, city)
а затем выполните следующий запрос:
SELECT id, name
FROM customer
WHERE city = 'My City';
как этот запрос использует индекс с несколькими столбцами или не использует его, если индекс не создан как (город, идентификатор, имя) или (город, имя, идентификатор) вместо?
Ответы
Ответ 1
Представьте, что ключ представлен кортежем Python (col1, col2, col3)... операция индексирования включает в себя сравнение tuple_a
с tuple_b
..., если вы не знаете, какое значение col1 и col2, который вам интересен, но только col3, тогда он должен будет прочитать весь индекс ( "полное сканирование индекса" ), что не так эффективно.
Если у вас есть индекс (col1, col2, col3), вы можете ожидать, что любая RDBMS будет использовать индекс (прямо), когда предложение WHERE содержит ссылку на (1) все 3 столбца (2) оба col1 и col2 (3) только col1.
В противном случае (например, только col3 в предложении WHERE) либо RDBMS вообще не будет использовать этот индекс (например, SQLite), либо выполнит полное сканирование индекса (например, Oracle) [если другой индекс лучше].
В вашем конкретном примере, предполагая, что идентификатор является уникальным идентификатором клиента, бессмысленно указывать его в индексе (кроме индекса, который ваша СУБД должна настроить для первичного ключа или столбца, отмеченного как UNIQUE).
Ответ 2
В большинстве реализаций ключ представляет собой просто более длинный ключ, который включает все значения ключа, с разделителем. Нет волшебства, -)
В вашем примере значения ключа могут выглядеть примерно как
"123499|John Doe|Conway, NH"
"32144|Bill Gates| Seattle, WA"
Одна из характеристик этих индексов с составными ключами заключается в том, что промежуточные узлы дерева могут использоваться в некоторых случаях для "покрытия" запроса.
Например, если запрос заключается в том, чтобы найти имя и город с идентификатором, поскольку идентификатор является первым в индексе, индекс может эффективно выполнять поиск. Однажды в промежуточном node он может "анализировать" имя и город, от ключа, и не нужно идти в лист node, чтобы читать то же самое.
Если, однако, запрос хотел также отобразить номер телефона, тогда логика будет следовать за листом, когда будет найдена полная запись.
Ответ 3
В Oracle можно использовать составной индекс ключа, даже если ведущие столбцы не фильтруются. Это делается с помощью трех механизмов:
- Быстрое сканирование полного индекса, в котором многоблочные чтения используются для перемещения по всему сегменту индекса.
- Полное сканирование индекса, в котором индекс читается в логическом порядке блоков (я считаю, что прочитал, что в последних версиях Oracle может использовать для этого многоблочные чтения, но на самом деле вам следует рассчитывать на одноблочные чтения)
- Сканирование inddex skip, при котором очень низкая мощность для неосновных ведущих столбцов позволяет Oracle выполнять несколько сканирований диапазона индексов, по одному для каждого уникального значения ведущего столбца. Это довольно редко в моем опыте.
Ищите статьи Ричарда Фута или Джонатана Льюиса для получения дополнительной информации о внутренних компонентах Oracle.
Ответ 4
Некоторые реализации просто объединяют значения в порядке столбцов с разделителями.
Другим решением является простое b-дерево внутри b-дерева. Когда вы попадаете в лист в первом столбце, вы получаете как список совпадающих записей, так и мини-b-дерево следующего столбца и т.д. Таким образом, порядок столбцов, указанных в индексе, имеет огромное значение для того, будет ли этот индекс полезен для определенных запросов.
Вот связанный с этим вопрос, который я написал на прошлой неделе:
Сбрасывается ли SQL Server при использовании составного кластерного индекса?
Ответ 5
Помимо описанного выше механизма "составного ключа", одна из возможностей - это kdtree
, которая работает как двоичное дерево, но по мере прохождения каждого уровня вы проходите через измерения k
. То есть первый уровень дерева разделяет первое измерение на две части, второй уровень разделяет второе измерение, уровень k+1
th снова разделяет первое измерение и т.д. Это позволяет эффективно разбивать данные на любое число размеров. Этот подход распространен в "пространственных" базах данных (например, Oracle Spatial, PostGIS и т.д.), Но, вероятно, не так полезен в "обычных" многоиндексных таблицах.
http://en.wikipedia.org/wiki/Kd-tree
Ответ 6
Он может использовать индекс (id, name, city) для удовлетворения предиката City =?, но очень неэффективно.
Чтобы использовать индекс для удовлетворения этого запроса, ему нужно будет пройти большую часть древовидной структуры, ища записи с нужным городом. Это, вероятно, порядок magnatude быстрее, чем сканирование таблицы!
Индекс (city, name, id) будет лучшим индексом для вашего запроса. Он легко найдет все требуемые записи города и не будет нуждаться в доступе к базовой таблице, чтобы получить значения id и name.