Pull to refresh

Comments 7

Clustered Index по своей сути это упорядоченная «куча» с удобным механизмом поиска по интересующему вас полю. Т.е. при создании кластеризованного индекса строки на страницах кучи сортируются и выстраиваются в нужной последовательности, а сверху появляется «шапка» b-tree. Куча превращается в отсортированную последовательность строк.

Отсюда вытекает ответ на ваш вопрос. К heap можно применить только одно правило сортировки, следовательно кластеризованный индекс может быть только один. Некластеризованные индексы содержат копию данных, и именно копия данных сортируется по новым правилам. Ну а для поддержания целостности, копия данных должна ссылаться на оригинал (на строки кластеризованного индекса).
У меня ещё небольшая часть со щелчком встала на место :). Спасибо!
Очевидно, таким методом создать кластеризованный индекс можно только один раз.
Ох, что-то у вас и правда каша какая-то с середины статьи пошла :)
В ORACLE есть ROWID — единственный способ найти строку таблицы.
В SQL Server таких способа два.
1. поиск по RID (8 байт)
2. поиск по ключу кластеризованного индекса (для простоты будем считать его уникальным и типа int — 4 байта)

В итоге у нас экономия 4 байта на каждой строке + 4 байта для каждой строки каждого индекса по таблице.

Дальше, как вы заметили, мы получаем отсортированную таблицу.
Пример: select id,name from sample_table where id between 1 and 100
а) таблица имеет кластерный индекс по полю id
план — Clustered Index Seek
b) таблица имеет уникальный некластерный индекс по полю id
план- Index Seek + RID Lookup

Ну и напоследок, все что описано выше сильно упрощено.
Например, считываются не просто страницы, а блоки страниц. Кроме того SQL Server использует упреждающее чтение. Ну и еще кучу всего в чем ему могут сильно помочь кластерные индексы.
Сейчас буду не соглашаться :).

>В SQL Server таких способа два.
1. Эти способы не могут быть использованы одновременно. Если на таблице есть кластеризованный индекс, row id использовать нельзя по очевидным причинам: RID может изменяться при редактировании.

>В ORACLE есть ROWID — единственный способ найти строку таблицы.
2. В Oracle есть index-organized tables — абсолютно аналогичная конструкция. В ней тоже ROWID не будет постоянным и поэтому не будет использоваться для доступа к данным. Поэтому тут по способам паритет.

> для простоты будем считать его уникальным и типа int — 4 байта
3. Эта та простота, которая временами оказывается хуже воровства :). Не дай Бог Вам придётся выбирать большие диапазоны по *другому* полю, когда эти id идут сильно не подряд. Кластеризованный индекс начнёт мешать, оптимизатор быстро предложит сделать покрывающий индекс для этого запроса — и Вы, скорее всего, прислушаетесь, потому что это сильный прирост скорости. Но куда логичнее было бы сделать именно этот индекс для сканирования не покрывающим, а кластеризованным, Проигрыш на поиске одного значения невелик, выигрыш на сканировании — существенен.

> Ну и напоследок, все что описано выше сильно упрощено.
4. Вот тут спорить не буду.
IOT не абсолютно аналогичная конструкция, но во многом схожая. Почитайте Тома Кайта да и в инете много информации об этом. Смысл аналогии к ORACLE был не в том чтобы сравнивать продукты. А показать ключ к пониманию.
Тема кластерного индекса уже много раз обсуждалась в просторах инета, что смысла разводить здесь треп нет никакого.

По пункту 3 — не дай Вам Бог делать составной кластерный индекс. А вот кластерный индекс по первичному ключу в 99% дает выигрыш. Это подтверждает и мой опыт и best practice Microsoft.
Во-первых, спасибо за ответ. Не иронизирую.

IOT не абсолютно аналогичная конструкция, но во многом схожая.
1. Ключевое отличие — возможность выноса данных в Overflow segment. Если это не делать — получается просто один в один.
2. Вы по-прежнему утверждаете, что в случае IOT доступ к записи осуществляется по ROWID :)?

Почитайте Тома Кайта да и в инете много информации об этом.
Мне кажется, или Вы мне предлагаете искать аргументы в поддержку вашей позиции? :)

По пункту 3 — не дай Вам Бог делать составной кластерный индекс.
Собственно, а почему?
Вот реальная структура.

[Publication_ID] int NOT NULL,
[name] nvarchar(255) COLLATE Cyrillic_General_CI_AS NOT NULL,
[Added] datetime NULL DEFAULT (sysdatetime()),
[status] int NULL,
[type] int NOT NULL DEFAULT ((1)),

Первичный ключ в ней составной — однозначно запись будет идентифицировать [Publication_ID] и [name]. Именно по этим двум полям мне нужен индекс, и это единственный индекс, который мне нужен. Почему мне не следует сделать составной первичный ключ, основанный на составном кластеризованном индексе?

А вот кластерный индекс по первичному ключу в 99% дает выигрыш.
По ощущениям, Вы воспринимаете первичный ключ как специальное 4-байтовое целое, предназначенное для идентификации записей. По ощущениям, Вы противопоставляете составной индекс и индекс по первичному ключу. И по ощущениям, статистику Вы взяли с потолка :).

Если ощущения мои ошибочны, сообщите мне об этом. Я подумаю ещё :).
Для IOT используется UROWID (логический ROWID). Ключевое отличие в том, что вторичный индекс по IOT просто нет смысла делать asktom.oracle.com/pls/asktom/f?p=100:11:0%3A%3A%3A%3AP11_QUESTION_ID:3187583300346869958

По п.3 потому что, если Вам понадобится сделать обычный индекс, например, по полю status, то его размер будет очень не оптимальный т.к. на каждую запись в индексе придется хранить [Publication_ID]+[name]+status. А стремиться надо к меньшим размерам, только тогда будет минимум дисковых чтений и больше производительность.

Sign up to leave a comment.

Articles