SQL INDEX - як це працює?


19

Мої знання баз даних і SQL базуються в більшості на університетських класах. Так чи інакше, я провів кілька місяців (майже рік) в компанії, де працював з базами даних.

Я прочитав кілька книг , і я взяв участь в декількох тренінгах про базах даних , таких як MySQL, PostgreSQL, SQLite, Oracleа також кілька nonSQL dbроків такі компанії MongoDB, Redis, і ElasticSearchт.д.

Як я вже сказав, я починаючий, маю багато нестачі знань, але сьогодні хтось щось сказав, що суперечить моїм знаходженцям.

Дозволь пояснити. Візьмемо базу даних SQL і створимо просту таблицю Personз кількома записами всередині:

id | name   | age
-----------------
1  | Alex   | 24
2  | Brad   | 34
3  | Chris  | 29
4  | David  | 28
5  | Eric   | 18
6  | Fred   | 42
7  | Greg   | 65
8  | Hubert | 53
9  | Irvin  | 17
10 | John   | 19
11 | Karl   | 23

Тепер це частина, на якій я хотів би зосередитись - idце та INDEX.

Поки я вважав, що це працює таким чином: коли створюється таблиця, INDEXце порожній. Коли я додаю новий запис до своєї таблиці INDEX, перерахунок проводиться на основі деяких алгоритмів. Наприклад:

Групування по одному:

1    ... N
N+1  ... 2N
     ...
XN+1 ... (X+1)N

так, для мого прикладу з size = 11 elementsі N = 3це буде так:

id | name   | age
-----------------
1  | Alex   | 24     // group0
2  | Brad   | 34     // group0
3  | Chris  | 29     // group0
4  | David  | 28     // group1
5  | Eric   | 18     // group1
6  | Fred   | 42     // group1
7  | Greg   | 65     // group2
8  | Hubert | 53     // group2
9  | Irvin  | 17     // group2
10 | John   | 19     // group3
11 | Karl   | 23     // group3

Отже, коли я використовую запит, SELECT * FROM Person WHERE id = 8він зробить простий розрахунок 8 / 3 = 2, тому ми повинні шукати цей об’єкт, group2і тоді цей рядок буде повернуто:

8  | Hubert | 53

введіть тут опис зображення

Цей підхід працює в той час, O(k)коли k << size. Звичайно, алгоритм впорядкування рядків по групах, безумовно, набагато складніший, але я думаю, що цей простий приклад показує мою точку зору.

Тож зараз я хотів би представити інший підхід, який мені показали сьогодні.

Візьмемо ще раз цю таблицю:

id | name   | age
-----------------
1  | Alex   | 24
2  | Brad   | 34
3  | Chris  | 29
4  | David  | 28
5  | Eric   | 18
6  | Fred   | 42
7  | Greg   | 65
8  | Hubert | 53
9  | Irvin  | 17
10 | John   | 19
11 | Karl   | 23

Тепер ми створюємо що - щось подібне Hashmap(насправді, в буквальному сенсі це Hash Map) , який відображає idдо addressрядка з цим ідентифікатором. Скажімо:

id | addr 
---------
1  | @0001
2  | @0010
3  | @0011
4  | @0100
5  | @0101
6  | @0110
7  | @0111
8  | @1000
9  | @1001
10 | @1010
11 | @1011

Отже, коли я запускаю запит: SELECT * FROM Person WHERE id = 8

він буде відображатись безпосередньо id = 8для адреси в пам'яті, і рядок буде повернутий. Звичайно, складність цього є O(1).

Тож зараз у мене мало питань.

1. У чому полягають переваги та недоліки обох рішень?

2. Яка з них більш популярна в поточних реалізаціях бази даних? Можливо, різні dbs використовують різні підходи?

3. Чи існує він у dbs, що не є SQL?

Заздалегідь спасибі


ПОРІВНЯЙТЕ

               |      B-tree     |   Hash Table
----------------------------------------------------
----------------   one element   -------------------
----------------------------------------------------
SEARCHING      |  O(log(N))      | O(1) -> O(N)  
DELETING       |  O(log(N))      | O(1) -> O(N)
INSERTING      |  O(log(N))      | O(1) -> O(N)
SPACE          |  O(N)           | O(N)
----------------------------------------------------
----------------    k elements   -------------------
----------------------------------------------------
SEARCHING      |  k + O(log(N))  | k * O(1) -> k * O(N)
DELETING       |  k + O(log(N))  | k * O(1) -> k * O(N)
INSERTING      |  k + O(log(N))  | k * O(1) -> k * O(N)
SPACE          |  O(N)           | O(N)

N - кількість записів

Я правий? А як щодо вартості відновлення таблиці B-tree та Hash після кожного вставки / видалення ? У випадку з B-деревом ми повинні змінити деякі вказівники, але у випадку збалансованого b-дерева йому потрібно більше зусиль. Також у випадку таблиці Hash нам потрібно зробити кілька операцій, особливо, якщо наша операція породжує конфлікти .


2
По-другому, ви описуєте хеш-індекс. Частина про O(1)вас зрозуміла правильно! Спочатку, здається, ви описуєте індекс B-дерева, але у вас є непорозуміння. Немає розрахунку (поділ на 3 чи що-небудь), він складніший, оскільки дерево має більше рівнів (це дерево, воно має великі, маленькі, менші гілки, ..., а потім залишає :)
ypercubeᵀᴹ

3
BTrees: en.m.wikipedia.org/wiki/B-tree здивований, що у вашому університеті не було курсу алгоритмів, який би пояснив це
Філ

@ypercube Привіт, дякую за вашу відповідь. Як і я писав: Of course, an alghoritm to organise rows in groups is for sure much more complicated but I think this simple example shows my point of view.Звичайно, я знаю, що це набагато набагато складніше. Отже, нарешті, коли я кажу в коді, INDEXяке з моїх рішень ( 1-е чи 2-е ) ближче до справжнього? А як щодо часу, необхідного для доступу до запису на основі INDEX. Це насправді O(1)? З індексом B-дерева це дуже схоже O(log2(N)). Я правий?
ruhungry

@FreshPhilOfSO Я здогадуюсь (навіть більше, я впевнений) це були деякі лекції з цього приводу. Напевно, я щось пропустив ...
ruhungry

ElasticSearch використовує перевернуті індекси, абсолютно різні, ніж B-дерева elastika.co/blog/found-elasticsearch-from-the-bottom-up
Martinez

Відповіді:


12

Ви в основному описуєте індекс B-дерева та хеш-індекс. Їм обом є місце, але обидва найкраще підходять для різних робіт.

Переваги і недоліки

Індекси B-дерева (і B + -триці) зазвичай збалансовані. Це означає, що пошук значення завжди займе стільки ж часу, незалежно від того, де в дерево воно падає (O (log n)). Як правило, кількість рівнів у дереві обмежена, тому воно, як правило, «ширше», а не «глибше». Однак для невеликих наборів даних вартість обслуговування та використання B-дерева може бути більше, ніж просто читання всіх рядків. Індекси B-дерева хороші для великих наборів даних, наборів даних з низькою селективністю або наборів даних, де ви маєте намір вибрати коло об'єктів, а не лише один об’єкт.

Таблиці хешу чудово підходять для невеликих наборів даних. Хеш-індекси мають заздалегідь задану кількість хеш-ковшів, залежно від використовуваного алгоритму хешування. Це тому, що заданий алгоритм хешу може створити лише стільки унікальних хешів, тому він стає лише «глибшим», а не «ширшим». Після того, як двигун бази даних знайде потрібне відро, він проходить через усі об'єкти в цьому відрі, щоб знайти потрібний. З невеликими, високоселективними наборами даних кожне відро містить дуже малу кількість об'єктів і вирішується досить швидко. З більшими наборами даних відра отримують значно більшу кількість людей. Отже, якщо потрібний вам предмет знаходиться у невеликому відрі або знаходиться біля початку відра, він повертається досить швидко. Якщо він знаходиться в кінці великого відра, це займе більше часу. Індекс не врівноважений, тому продуктивність становить від O (1) до O (n).

Популярність

Взагалі я найбільше перебігав B-дерева. Індекси растрових зображень - це також інший варіант для значень з низькою кардинальністю (подумайте, булеві або, можливо, гендерні). Це змінюватиметься залежно від двигуна вашої бази даних щодо того, які типи індексів доступні.

NoSQL

Бази даних NoSQL безумовно підтримують індекси. Більшість підтримує B-дерево або варіацію B-дерева. Здається, більшість також підтримує хешовані індекси.


4
Я не думаю, що кількість рівнів у B + деревах фіксована. Принаймні, не в SQL-сервері, наскільки я знаю.
ypercubeᵀᴹ

1
Це правда. Дерево В може мати будь-яку кількість рівнів, але воно, як правило, обмежене 3 або 4. Я відредагував свою відповідь.
сарме

Привіт @sarme. Мені дуже подобається ваша відповідь. Це багато пояснює. Не заперечуєте, якщо я починаю щедро за це питання? Можливо, хтось додасть щось цікаве.
ruhungry

1
Ви не маєте на увазі низьку кардинальність для індексу растрових зображень?
Михай

1
Правильно, НИЗЬКА кардинальність. Я маю припинити відповідати на питання безпосередньо перед сном :). Відповідь оновлено.
сарме

4

Які є переваги та недоліки обох рішень? Друге рішення не може виконати сканування діапазону. Він чудово підходить для вибору одного ідентифікатора. Але що робити, якщо ви хочете ідентифікатори від 3 до 8? Він повинен захопити всі записи окремо, які в реальному світі не просто O (1) * 6 записів для отримання. У великій виробничій базі даних з індексом HashMap ви отримаєте записи на різних сторінках, вимагаючи, щоб ви потрапили на диск і прочитали шість різних сторінок в пам'яті.

У структурі B-Tree, наприклад, як реально буде реалізована ваша перша ситуація, ідентифікатори будуть послідовними на диску, і одна сторінка, ймовірно, містить ідентифікатори 3 - 8, збільшуючи швидкість сканування діапазону, зробить індивідуальний доступ O (журнал n) .

Який із них більш популярний у поточних реалізаціях бази даних? Можливо, різні dbs використовують різні підходи? Я не маю величезного досвіду в багатьох різних базах даних. Я знаю, що сервер Sql в основному використовує B-Trees, але в SQl 2014 є кілька нових Hash Indexes, які ви можете використовувати в певній таблиці. Я чую дуже багато баз даних Sql і кешування баз даних, побудованих на отриманні окремих записів, також використовують хеш-індекси. Це має сенс для кешів, оскільки ви хочете запис для користувача A і не потребуєте сканування діапазону.

Чи існує він у dbs не-SQL? Так. Швидкий погляд на документацію створення індексу для postgressql, я бачу, що вона підтримує як Hash, так і B-Tree індекси, а також кілька інших.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.