Header RSS-подписка на обновления сайта eMail-подписка на обновления сайта

К вопросу уникальности индексов. Часть 4/4.

  • Другие части статьи:
  • 1
  • 2
  • 3
  • 4
  • вперед »

Так вот, давайте изучим эту самую первую запись (строку) нашей тестовой таблицы. Напомню, что согласно предположению последнего абзаца предыдущей части статьи, движок должен был считать ключ кластерного индекса этой строки (col1=10000) уникальным, хотя буквально следующая же строка «развеяла» бы такое допущение. Итак — вот она, строка с «возможно уникальным» ключом:

10000c00 10270000 20a10700 0300 00

Что мы видим?

  • 10000c00 — снова заголовок строки, разумеется. Снова NULL bitmap — присутствует, а вот плавающих колонок больше нет! Да, пятый бит первого байта очищен, а это значит у нас имеются колонки только фиксированных размеров;
  • 10270000 и 20a10700 — col1 и col2 соответственно, со своими значениями 10000 и 500000.
  • 0300 — как ни удивительно, но снова — общее число колонок. Которых снова 3. Ну да, как там в классике — «...видишь? И я не вижу. А он — есть!». :) Так вот «он» (в данном случае она, колонка UNIQUIFIER) — таки есть;
  • 00 —снова NULL bitmap, снова рапортующий о тотальном отсутствии значений NULL в записи.

Итого, что бы прояснить картину: для пока уникальной записи не-уникального ключа UNIQUIFIER отсутствует. Физически он отсутствует абсолютно, его эфемерное присутствие выражается разве что в счетчике колонок. Логически, с точки зрения автора, удобнее считать что UNIQUIFIER для такой записи содержит ноль. Всегда помня, однако, что физически это не ноль, и даже не NULL, а еще меньше. :) Справедливости ради отметим, что это не какое-то «особое» изобретение для «особой» колонки. Движок вообще опускает (на физическом уровне) все колонки «плавающих» (но не фиксированных!) размеров содержащие значения NULL. Как мы видим, для нужд «уникализации» такое поведение пришлось очень, очень «в кассу», иначе необходимость включения в кластерный индекс не-уникальной колонки вызывало бы у DBA беспросветную тоску. А так, с учетом что раз мы создаем по колонке индекс, тем более кластерный, то, наверно, можно говорить о хотя бы относительной уникальности значений в ней содержащихся — все не так уж плохо. Да, дубликаты «ощипают» наш HDD, и порядочно. Однако все уникальные (пока) значения присутствия UNIQUIFIER-а не почувствуют! Последний разобранный нами слот занимает 15 байт, ровно столько же сколько и его «коллега» из уникального кластерного индекса.

Разобравшись с индексом кластерным и его «эрзац-уникализатором», а так же вооруженные знаниями по структуре уникального не-кластерного индекса из самого первого опыта, мы можем предсказать, как будет выглядеть индекс NONCL_uq_Index в опыте текущем. На не-листовых уровнях этому индексу не требуется ни «уникализатор» (он сам по себе уже уникальный), ни ссылки на кластерный ключ. Стало быть, записи этих уровней будут выглядеть точно как и в первом опыте. Вот, к примеру, записи корневой страницы разбираемого индекса (эта страница имеет номер 1259):

PageId  Level   ChildPageId col2 (key)
1259    2       110         NULL
1259    2       1260        585751

То есть на всех не-листовых уровнях фигурирует только ключ не-кластерного индекса состоящий ровно из одной колонки — col2. Что совершенно совпадает с тем, как был этот индекс устроен, во времена когда оба индекса были уникальными.

Все несколько меняется, когда дело доходит до листового уровня. Нет, общая идея сохранилась: каждый ключ не-кластерного индекса должен сослаться на соответствующий ему ключ индекса кластерного, дабы через последний иметь доступ к остальной части таблицы. Вот только кластерный ключ теперь, в отличии от первого опыта, стал составным. И записи листового уровня выглядят теперь вот как:

PageId  Level   col2 (key)  col1    UNIQUIFIER
90      0       500000      10000   0
90      0       500001      10000   1
90      0       500002      10000   2
90      0       500003      10000   3
...     ...     ...         ...     ...
90      0       500010      10010   0
90      0       500011      10010   1
90      0       500012      10010   2
...     ...     ...         ...     ...
90      0       500020      10020   0
90      0       500021      10020   1
...     ...     ...         ...     ...
90      0       500030      10030   0
90      0       500031      10030   1
...     ...     ...         ...     ...
90      0       500040      10040   0
90      0       500041      10040   1
...     ...     ...         ...     ...

Итого: ключ кластерного индекса включается полностью, как он есть, на листовой уровень не-кластерного индекса. Однако роль этого ключа именно что «перекинуть мостик» от не-кластерного индекса к остальной части таблицы. Он не становится частью не-кластерного ключа, как это было в предыдущем случае, ведь нам не требуется «уникализация» записей текущего индекса. С точки зрения занимаемого места на HDD дела на этом листовом уровне снова «не блеск», как можно догадаться. Но много, много лучше чем могло бы быть. А именно, те слоты у которых согласно последнему резалт-сету в колонке UNIQUIFIER содержится 0 (на самом деле NULL) занимают те же 12 байт, что и в самом первом нашем эксперименте. Потому что для них указанной колонки как бы нет (или она для них «как бы есть», тут уж решайте сами насчет формулировки). Но вот если значение UNIQUIFIER-а отличается от 0/NULL, то объем занимаемого места «подпрыгивает» к отметке 20 байт. Ну а чего вы ждали? Плюс четыре байта на само значение, и плюс четыре байта на обеспечение «плавающего» размера — все верно.

Вывод? Все тот же: делая колонку гарантировано уникальной проиграть вы не можете, а выиграть — запросто. Если же колонка планируется под именно кластерный индекс то можно говорить не просто о выигрыше, а почти о джек-поте. Жаль только, что в общем случае влиять на характеристику уникальности колонки мы почти не можем, она практически однозначно диктуется правилами бизнеса. Мы, разумеется, можем ввести «лишнюю» колонку, именно и только для создания кластерного индекса. Как покажет дальнейшее изложение эта идея почти всегда будет здравой, если уж у нас не «вытанцовывается» «естественно-уникальная» колонка типа «номер паспорта сотрудника». Кроме того, и теперь вы это знаете, «лишняя» колонка будет введена и без вашего желания, так чего «тянуть»? Правда, если колонка по которой мы планируем создать кластерный индекс будет содержать «почти уникальные» значения, хотя и не будет официально объявляться как UNIQUE, «профит» именно от UNIQUIFIER-колонки (а не своей собственной) можно получить вполне ощутимый, ведь при таком сценарии ее «почти не будет»! Одним словом — выбор за нами, как и всегда. Главное знать альтернативы и критерии по которым мы эти альтернативы выбираем.

Оба индекса не-уникальны.


366bef3a

Наконец — четвертая вариация сочетания уникальности двух индексов, сводящаяся к полному отсутствию уникальности. Поскольку, очевидно, этот опыт есть комбинация последнего и предпоследнего экспериментов раздел будет совсем коротким. Код тестового скрипта для экономии приводится не будет, он без проблем пишется самостоятельно на основе предыдущих скриптов. Перейдем сразу к выводам.

Несложно догадаться, что этот случай берет худшие черты двух предыдущих, что и выливается в «трехэтажность» каждого из индексов и в общее число страниц не-листового уровня равного десяти. По пять «на брата». А ведь начинали с четырех — три страницы для кластерного и одна для противоположного индекса!

Не менее простым представляется и такое умозаключение: кластерный индекс по сравнению с только что разобранным не изменился ни на йоту. Все тот же UNIQUIFIER сверху донизу, со всеми своими полюсами и минусами. Так что переходим сразу к индексу не-кластерному.

Что касается не-листовых уровней, то тут изменения самые заметные: наш составной кластерный ключ теперь является составной частью не-кластерного ключа. Обратите внимание: мы заказывали ключ из одной колонки (col2), а получили — из трех! col2+col1+UNIQUIFIER. И ведь все верно, не придерешься! Итого, вот как выглядят записи, скажем, root-страницы разбираемого индекса:

PageId  Level   ChildPageId col2 (key)  col1 (key)  UNIQUIFIER (key)
794     2       110         NULL        NULL        NULL
794     2       795         551450      61450       1
794     2       1083        602510      112510      9
794     2       1370        653580      163580      8

Обратите внимание, что все колонки — ключ, а не «просто так». Нужно ли заострять внимание на том, что для хранения страниц не-листовых уровней такой «финт» имеет самые отрицательные последствия в плане объема места требуемого на HDD?

Листовой же уровень все того же не-кластерного индекса, напротив, очень похож на только что виденный. По сути изменения только два: в заголовках столбцов col1 и UNIQUIFIER появился суффикс (key) в каждом. То есть ранее это был именно «мостик», теперь — просто часть ключа (но и снова «мостик», по совместительству). По счастью, на хранении данных этого уровня такой суффикс никак не сказался. Слот по прежнему занимает 12 байт если наш «эрзац-уникализатор» равен 0/NULL, либо 20 байт в обратном случае.

Не-кластерный индекс на хип (heap) таблице.

В заключительном разделе статьи мы разберем структуру индекса на хип таблице. Поскольку такая таблица по своему определению кластерного индекса не имеет, то в рамках этого заключительного раздела мы будем говорить просто «индекс», без уточнения что имеется в виду его не-кластерная разновидность. Наши исследования помогут прояснить один важный момент: почему настоятельно рекомендуются (в том числе и официально Microsoft) таблицы с кластерным индексом. А хип-таблицы, как им противоположные, соответственно — не рекомендуются совсем. Иными словами: «создаешь таблицу? сразу реши вопрос с колонкой (или несколькими, в данном контексте не важно) кластерного индекса!». Почему так и откуда такая настойчивая рекомендация проистекает мы сейчас и выясним. Только учтем, что хотя индекс у нас остался строго один, не-кластерный, ничто не может ему помешать быть в одиночестве как уникальным, так и нет. Поэтому наше заключительное исследование вновь подразделяется на два варианта: не-кластерный не-уникальный и не-кластерный уникальный. Начнем с последнего.

Уникальный индекс на хип таблице.

На этот раз тестовый скрипт будет таким:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
USE master
go
CREATE DATABASE [~DB~]
ON PRIMARY (
    NAME = '~DB~_Data',
    FILENAME = 'c:\sqlCMD.ru\~DB~.mdf',
    SIZE = 20 MB )
LOG ON (
    NAME = '~DB~_Log',
    FILENAME = 'c:\sqlCMD.ru\~DB~.ldf',
    SIZE = 20 MB )
GO
USE [~DB~]
GO
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'T1') DROP TABLE T1
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Tsup') DROP TABLE Tsup
CREATE TABLE Tsup (PageFID  tinyint, PagePID int, IAMFID   tinyint, IAMPID  int, ObjectID  int, IndexID  tinyint, PartitionNumber tinyint,
 PartitionID bigint, iam_chain_type  varchar(30), PageType  tinyint, IndexLevel  tinyint, NextPageFID  tinyint, NextPagePID  int, PrevPageFID  tinyint, PrevPagePID int)
CREATE TABLE T1 (col1 int, col2 int)
GO
CREATE UNIQUE NONCLUSTERED INDEX NONCL_uq_Index ON T1(col2)
GO
declare @i int
SET @i = 0
BEGIN TRANSACTION
    WHILE @i < 250000 --loop counter
    BEGIN
        insert into T1 VALUES (999, 500000+@i)
        set @i += 1
     END
COMMIT TRANSACTION
INSERT INTO Tsup EXEC ('DBCC IND ([~DB~], T1, -1)');
SELECT PagePID,IndexID,PageType,IndexLevel FROM Tsup WHERE IndexLevel>0

Как и договорились — только не-кластерный, но уникальный индекс по колонке col2. Команда DBCC IND сообщает нам:

PagePID IndexID PageType    IndexLevel
94      2       2           1
1179    2       2           2
1180    2       2           1

Пока все представляется не столь и ужасным: всего три «этажа» (два мы видим и плюс листовой), всего 3 страницы не-листовых уровней — достойно! Ладно, посмотрим на устройство этих страниц изнутри. Для начала — «корень»:

1
2
DBCC TRACEON(3604)
DBCC PAGE([~DB~], 1, 1179, 3) --non-cluster idx, root level(2)

Видим, что:

PageId  Level   ChildPageId col2 (key)
1179    2       94          NULL
1179    2       1180        601025

И что? По моему — идеально. Единственная колонка в виде ключа, ссылка на дочернюю страницу... Меньше-то не бывает, если только мы в своих опытах ничего важного не упустили. Действительно, пока мы на не-листовых уровнях рассказы о «плохости» хип-таблиц представляются ничем не подтвержденными инсинуациями, не более того. Но посмотрим что у нас на уровне листовом. В случае автора первой страницей на нем была страница с номером 90, ее и смотрим:

1
2
DBCC TRACEON(3604)
DBCC PAGE([~DB~], 1, 90, 3) --non-cluster idx, leaf level(0)

И вот тут-то — «шоу начинается»:

PageId  Level   col2 (key)  HEAP RID
90      0       500000      0x5000000001000000
90      0       500001      0x5000000001000100
90      0       500002      0x5000000001000200
90      0       500003      0x5000000001000300
90      0       500004      0x5000000001000400
90      0       500005      0x5000000001000500
...     ...     ...         ...
90      0       500010      0x5000000001000A00
90      0       500011      0x5000000001000B00
...     ...     ...         ...
90      0       500020      0x5000000001001400
90      0       500021      0x5000000001001500
...     ...     ...         ...
90      0       500050      0x5000000001003200
90      0       500051      0x5000000001003300
90      0       500052      0x5000000001003400
...     ...     ...         ...
90      0       500080      0x5000000001005000
90      0       500081      0x5000000001005100
90      0       500082      0x5000000001005200
...     ...     ...         ...

Давайте сразу о «больном», о размерах: в наших прошлых четырех экспериментах в тех двух из них когда не-кластерный индекс был уникальным каждый его слот на листовом уровне занимал или 12 байт (когда второй, кластерный индекс был так же уникальным), или либо 12, либо 20 байт (когда кластерный индекс уникальным не являлся; выбор между этими двумя значениями был обусловлен, как вы помните, фактической уникальностью значения в колонке кластерного ключа). Поскольку «в среднем» индексы стараются создавать на колонках с более-менее уникальными значениями, то «в среднем», если бы T1 была реальной таблицей в промышленной системе, слот листового уровня занимал бы 12 байт иногда требуя еще 8. В случае отсутствия кластерного индекса, то есть в случае разбираемой в настоящий момент хип-таблицы, тот же слот занимает необсуждаемые 16 байт каждый, без вариантов. Так что, снова «в среднем», на каждый слот мы просто теряем 4 байта не получая в ответ никаких выгод. А откуда такая потеря проистекает? А оттуда, что раньше «мостиком» между записями не-кластерного индекса и остальной частью таблицы выступали ключи индекса кластерного, а теперь, сами видите, эту роль принял на себя загадочный HEAP RID. Который, пожалуй, заслуживает краткого описания в размере пары-тройки абзацев.

Стало быть — где у нас (а точнее у движка сервера) очередные «грабли»? А вот они: раньше кластерный ключ гарантированно и однозначно определял целевую строчку таблицы с которой следует произвести те или иные действия. Помните наш разговор про «хэндл»? А теперь такого хэндла — нету. Почему бы в такой роли не выступить колонке col2, спрашиваете вы? Тоже, на самом деле, уже обсудили — она не является гарантированно уникальной. Да, мы пометили индекс по ней как UNIQUE, но это — сегодня. А кто даст гарантии что завтра мы не передумаем? А вот с кластерным индексом вы можете думать, раздумывать, передумывать, снова обдумывать и делать вообще что угодно — по факту он гарантировано уникален. Стало быть — нужна замена. Встречайте — HEAP RID, та самая замена. RID расшифровывается как row ID, а иногда row locator, то есть, грубо, «определитель строки» (что, кстати говоря, и есть мета-задача обсужденного нами ранее «хэндла»). Ну а слово HEAP подчеркивает, что находится та строка в хипе и только там. В ином случае, согласитесь, нам никакие «заменители хэндлов» не требуются. Разумеется, значения HEAP RID имеют четко выраженную структуру занимающую всегда ровно 8 байт. Вот она: FileID(2):PageID(4):SlotNumber(2). Цифры в скобках означают число байт из восьми отводимую под эту часть структуры. Пример: строка с col2=500082 (последняя в резалт-сете выше) имеет HEAP RID=0x5000000001005200, «дешифруем» его:

  • первые четыре байта — номер страницы, в нашем случае 0x00000050=80;
  • следующие два — номер файла в котором «лежит» страница. У нас: 0x0001=1;
  • завершающая пара байтов — слот, 0x0052=82.

Итого, если бы мы дали запрос вида SELECT * FROM T1 WHERE col2=500082, то возвращаемые значение следовало взять в первом файле данных, на 80-й странице, в слоте номер 82. Многие удивляются что страница указывается не 90-я, которую мы исследуем в настоящий момент, а 80-я. «Разве col2=500082 находится не на 90-й?», спрашивают они. «Вот же она, я ее вижу!». Видят-то они видят, только они видят индексную запись с тем же значением. А нам нужна вся запись, то есть строка таблицы, со всеми нашими двумя колонками, которая хранится — где? Правильно — в хип таблице. Которая является структурой совершенно самостоятельной, хоть и связанной с разбираемым индексом. Что бы убедится, что вас не обманывают, вызовите для просмотра «внутренности» 80-й страницы:

1
2
DBCC TRACEON(3604)
DBCC PAGE([~DB~], 1, 80, 3) --the heap-table

Найдя на этой странице 82-й слот обнаруживаем там:

Slot 82 Column 1 Offset 0x4 Length 4 Length (physical) 4

col1 = 999                          

Slot 82 Column 2 Offset 0x8 Length 4 Length (physical) 4

col2 = 500082

Не обманули? ;) А самое главное — решение вновь совершенно рабочее. Потому что сочетание трех указанных компонентов (FileID:PageID:SlotNumber) снова гарантировано уникально что бы вы себе не думали и не передумывали.

Итак, по сравнению с кластерной таблицей в текущей ситуации существенное изменение только одно: подавляющее большинство записей листового (только) уровня требуют лишние 4 байта не предоставляя никаких выгод взамен. То есть просто выброшенное место на HDD. Однако — все работает (в смысле индекс корректно и однозначно извлекает целевые данные), это не отнять, и тут претензий никаких. Посмотрим на возможные изменения в случае индекса не-уникального на все той же хип-таблице.

Не-уникальный индекс на хип таблице.

Вооруженные знанием о «нелюбви» движка к любым не-уникальным индексам, почерпнутом в предыдущих разделах текущей статьи, большинство читателей уже, наверно, настроились на самое худшее. И хотя автор пессимистов не любит, в данном случае таких читателей правильно и корректно называть реалистами. :) Потому что как выяснится через минуту они совершенно правы в своих ожиданиях. Давайте к тестам:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
USE master
go
CREATE DATABASE [~DB~]
ON PRIMARY (
    NAME = '~DB~_Data',
    FILENAME = 'c:\sqlCMD.ru\~DB~.mdf',
    SIZE = 20 MB )
LOG ON (
    NAME = '~DB~_Log',
    FILENAME = 'c:\sqlCMD.ru\~DB~.ldf',
    SIZE = 20 MB )
GO
USE [~DB~]
GO
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'T1') DROP TABLE T1
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Tsup') DROP TABLE Tsup
CREATE TABLE Tsup (PageFID  tinyint, PagePID int, IAMFID   tinyint, IAMPID  int, ObjectID  int, IndexID  tinyint, PartitionNumber tinyint,
 PartitionID bigint, iam_chain_type  varchar(30), PageType  tinyint, IndexLevel  tinyint, NextPageFID  tinyint, NextPagePID  int, PrevPageFID  tinyint, PrevPagePID int)
CREATE TABLE T1 (col1 int, col2 int)
GO
CREATE NONCLUSTERED INDEX NONCL_NONuq_Index ON T1(col2)
GO
declare @i int, @j int
SET @i = 0
SET @j = 0
BEGIN TRANSACTION
    WHILE @i < 250000 --loop1 counter
    BEGIN
        WHILE @j < 10 --loop2 counter
        BEGIN
            insert into T1 VALUES (999, 500000+@i)
            set @j += 1
        END
        set @i += 10
        set @j = 0
    END
COMMIT TRANSACTION
INSERT INTO Tsup EXEC ('DBCC IND ([~DB~], T1, -1)');
SELECT PagePID,IndexID,PageType,IndexLevel FROM Tsup WHERE IndexLevel>0

Получаем:

PagePID IndexID PageType    IndexLevel
94      2       2           1
834     2       2           2
835     2       2           1
1135    2       2           1

Ну — все понятно, уже, на «ровном месте», добавилась лишняя страница не-листового уровня — сразу минус по сравнению с предыдущим вариантом. Ладно, смотрим «корень»:

1
2
DBCC TRACEON(3604)
DBCC PAGE([~DB~], 1, 834, 3) --non-cluster idx, root level(2)

Видим:

PageId  Level   ChildPageId col2 (key)  HEAP RID (key)
834     2       94          NULL        NULL
834     2       835         568030      0xD601000001005500
834     2       1135        636060      0x0C0300000100A500

В общем-то — это ожидалось, нам вновь нужен «эрзац-уникализатор», ведь наше «правило №1», очевидно, будет нарушено если оставить в ключе только значения col2. Но у нас нет удобного (или хотя бы относительно удобного) кластерного ключа годящегося на эту роль. А что у нас есть? Как всегда — его «сменщик», HEAP RID. «Прицепляем», «насильно вводим в ключ» и т.д. — логика совершенно та же самая что была в основной части рассказа, когда там не-кластерный индекс перестал быть уникальным. О сухом остатке таких изменений структуры читатели уже все поняли: «плюс восемь» к каждому слоту не-листового уровня, что и выливается в дополнительную страницу этого уровня. И, что характерно, взамен — никакого «профита», Снова одни расходы.

На уровне листовом, как можно себе представить, изменения минимальные:

PageId  Level   col2 (key)  HEAP RID (key)
90      0       500000      0x5000000001000000
90      0       500000      0x5000000001000100
90      0       500000      0x5000000001000200
...     ...     ...         ...

Если раньше HEAP RID был просто «мостиком» к хип-таблице и, как следствие, к основному массиву данных, то теперь, сохранив эту роль, он еще получил «повышение статуса» — стал частью ключа. По счастью, статус хотя бы не требует лишних байт, как занимал каждый слот этого уровня 16 байт, так и продолжает.

Итого, отмена уникальности индекса хип-таблицы приводит к дальнейшему «сжиганию» места на HDD, как следствие — снижению эффективности работы индекса, и, самое главное, отсутствию каких либо компенсаций за все эти неудобства. Ну разве «но все же работает!», если это вас утешит. Работает, по крайней мере за это можете не волноваться.

Вместо заключения: почему хип-таблица почти всегда плохо.

Итак, мы уже имели возможность убедиться, что идея «а давайте-ка мы вообще кластерный индекс заводить не будем» является «не айс», мягко выражаясь. Индексы от этого — растут, толку от этого — ноль (а более корректно сказать, что наносится неоспоримый ущерб системе, обсуждению подлежит лишь размер его, но не сам факт), какие еще доказательства нужны? Для самых въедливых читателей приведу ссылку на отличную статью, где сам Microsoft ставит опыты с кластерными и хип-таблицами (к сожалению — только english). А для читателей не столь въедливых ограничусь выводами из этих опытов. Итак, с точки зрения Microsoft (причем эта точка зрения подтверждена конкретными замерами конкретных таблиц), если на таблице есть кластерный индекс:

  • таблица и не-кластерные индексы работают быстрее;
  • места на HDD требуется меньше (тут читатели освоившие приведенный выше материал могут скромно заметить: «да мы уж в курсе» :) );
  • удаление строк таблицы высвобождает больше места на HDD.

Для таблицы кластерного индекса не имеющего, то есть для хип-таблицы, просто поменяйте в данном списке каждый пункт с «плюс» на «минус». Надо полагать, будет разумным допущение о том, что могут подобраться такие специфические обстоятельства и плюс такие структуры таблиц, и плюс такие наборы конкретных данных, что хип-таблицы все же будут оправданы в своем применении. Для того они и разрешены синтаксически и поддерживаются движком. Но в целом дискуссия закрыта: «создал таблицу — создал для нее кластерный индекс», все!

Автор традиционно благодарит своих читателей за внимание проявленное ими к материалам блога, и желает им быстрых запросов, оптимальных индексов и отсутствия в их базах хип-таблиц. Увидимся, пока!

  • Другие части статьи:
  • 1
  • 2
  • 3
  • 4
  • вперед »