SQL Server - Разделенные таблицы или кластерный индекс?
Предположим, что у вас есть одна массивная таблица с тремя столбцами, как показано ниже:
[id] INT NOT NULL,
[date] SMALLDATETIME NOT NULL,
[sales] FLOAT NULL
Также предположим, что вы ограничены одним физическим диском и одной файловой группой (PRIMARY). Вы ожидаете, что эта таблица проведет продажи для 10 000 000+ идентификаторов по 100 дат (легко 1B + записи).
Как и во многих сценариях хранилищ данных, данные, как правило, будут расти последовательно по дате (т.е. каждый раз, когда вы выполняете загрузку данных, вы будете вводить новые даты и, возможно, обновлять некоторые более поздние даты данных). В аналитических целях данные часто запрашиваются и агрегируются для случайного набора из ~ 10000 идентификаторов, которые будут указаны посредством соединения с другой таблицей. Часто эти запросы не указывают диапазоны дат или указывают очень широкие диапазоны дат, что приводит меня к моему вопросу: как лучше всего индексировать/разделять эту таблицу?
Я подумал об этом некоторое время, но застрял в противоречивых решениях:
Вариант №1:. Когда данные будут загружаться последовательно по дате, определите кластеризованный индекс (и первичный ключ) как [дата], [id]. Также создайте функцию/схему разделения "скользящего окна" в дате, что позволяет быстро перемещать новые данные в/из таблицы. Потенциально создайте некластеризованный индекс для id, чтобы помочь с запросом.
Ожидаемый результат №1:. Эта настройка будет очень быстрой для целей загрузки данных, но не оптимальная, когда дело доходит до аналитических просмотров, в худшем случае (без ограничений по датам, неудачным с запросом id), можно прочитать 100% страниц данных.
Вариант № 2:. Когда данные будут запрашиваться только для небольшого подмножества идентификаторов за раз, определите кластеризованный индекс (и первичный ключ) как [id], [date]. Не беспокойтесь, чтобы создать секционированную таблицу.
Ожидаемый результат №2: Ожидаемый огромный рост производительности, когда дело доходит до загрузки данных, поскольку мы не можем более быстро ограничивать дату. Ожидаемая огромная производительность, когда дело доходит до моих аналитических запросов, так как это минимизирует количество прочитанных страниц данных.
Вариант № 3: Кластеризованный (и первичный ключ) следующим образом: [id], [date]; Функция/схема разделения "скользящего окна" на дату.
Ожидаемый результат № 3: Не уверен, чего ожидать. Учитывая, что первый столбец в кластерном индексе имеет значение [id] и, следовательно, (я понимаю), данные упорядочены по идентификатору, я бы ожидал хорошей производительности из своих аналитических запросов. Однако данные разделяются по дате, что противоречит определению кластерного индекса (но все же выровнено, поскольку дата является частью индекса). Я не нашел много документации, которая говорит об этом сценарии, и какие, если таковые имеются, преимущества в производительности, которые я могу получить от этого, что подводит меня к моему окончательному вопросу о бонусе:
Если я создаю таблицу на одной файловой группе на одном диске с кластеризованным индексом в одном столбце, есть ли какая-либо польза (помимо переключения разделов при загрузке данных), которая возникает при определении раздела в том же столбце?
Ответы
Ответ 1
Эта таблица очень узкая. Если реальная таблица будет такой узкой, вы должны быть счастливы иметь сканирование таблицы вместо index- > lookups.
Я бы сделал это:
CREATE TABLE Narrow
(
[id] INT NOT NULL,
[date] SMALLDATETIME NOT NULL,
[sales] FLOAT NULL,
PRIMARY KEY(id, date) --EDIT, just noticed your id is not unique.
)
CREATE INDEX CoveringNarrow ON Narrow(date, id, sales)
Это обрабатывает точечные запросы с помощью запросов и широкодиапазонных запросов с ограниченным просмотром по критериям даты и критериям идентификатора. Нет никакого поиска записей из индекса. Да, я удвоил время записи (и используемое пространство), но это прекрасно, imo.
Если вам нужна определенная часть данных (и эта необходимость продемонстрирована профилированием!), я бы создал кластерное представление, нацеленное на этот раздел таблицы.
CREATE VIEW Narrow200801
AS
SELECT * FROM Narrow WHERE '2008-01-01' <= [date] AND [date] < '2008-02-01'
--There is some command that I don't have at my finger tips to make this a clustered view.
Кластеризованные представления могут использоваться в запросах по имени, или оптимизатор будет использовать кластерные представления, когда предложения FROM и WHERE являются подходящими. Например, этот запрос будет использовать кластерное представление. Обратите внимание, что базовая таблица упоминается в запросе.
SELECT SUM(sales) FROM Narrow WHERE '2008-01-01' <= [date] AND [date] < '2008-02-01'
В качестве индекса вы можете удобно использовать определенные столбцы... Кластеризованное представление позволяет вам удобно использовать определенные строки.
Ответ 2
Кластеризованный индекс даст вам преимущества в производительности для запросов при локализации ввода-вывода. Дата является традиционной стратегией разделения, так как многие запросы D/W просматривают движения по дате.
Практическое правило для многораздельной таблицы предполагает, что размер разделов должен составлять около 10 м строк.
Было бы необычно видеть много прироста производительности от кластерного индекса при разнообразной аналитической нагрузке. Оптимизатор запросов будет использовать метод 'Index Intersection', чтобы выбирать строки, даже не попав в таблицу фактов. См. здесь для сообщения, которое я сделал по другому вопросу, который объясняет это более подробно с некоторыми ссылками.
Кластеризованный индекс может участвовать или не участвовать в пересечении индексов, поэтому вы можете обнаружить, что он довольно мало влияет на общую рабочую нагрузку на запрос.
Вы можете найти обстоятельства при загрузке, когда кластеризованные индексы дают вам некоторую выгоду, особенно если вы получили вычисления (например, Earned Premium), которые вычисляются в процессе ETL. В этом случае вы можете получить некоторые преимущества. Если у вас есть определенный запрос, который, как вы знаете, будет выполняться все время, это может иметь смысл использовать кластерные индексы для этого. Варианты № 2 и № 3 будут только значительно приносить вам пользу, если вы ожидаете, что этот тип запросов будет подавляющим большинством работы, выполняемой приложением.
Для гибкой системы простой сегмент диапазона дат с индексом ID (и датой, если разделы имеют диапазон, вероятно, обеспечит вам такую же производительность, как и любой другой). Вы можете получить некоторую выгоду от кластеризации ограниченных по индексу обстоятельств Вы также можете получить некоторый пробег от создания куба над данными и обеспечения правильной настройки агрегатов для этого запроса.
Ответ 3
Если вы используете разделы в операторах выбора, вы cn получаете некоторую скорость.
Если вы не используете его, используйте только "стандартные", тогда у вас нет пользы.
По вашей первоначальной проблеме: я бы порекомендовал вам вариант №1 с некластеризованным индексом по включенному идентификатору.
Ответ 4
Я бы сделал следующее:
- Некластерный индекс на [Id]
- Кластеризованный индекс в [Дата]
- Преобразуйте тип данных [sales] в числовой, а не в float
Ответ 5
Разделите таблицу по дате. Несколько горизонтальных разделов будут более результативными, чем одна большая таблица с таким количеством строк.
Ответ 6
Кластеризованный индекс в столбце даты не подходит, если у вас будут вставленные вставки, которые будут вставлены быстрее, чем разрешение datetime 3,33 мс.
если вы это сделаете, вы получите 2 ключа с одинаковым значением, и ваш индекс должен будет получить еще один внутренний уникальный идентификатор, который увеличит его размер.
я бы пошел С# 2 ваших вариантов.