Производительность индексирования BigInt vs VarChar - PullRequest
7 голосов
/ 22 октября 2009

Это таблица FACT в хранилище данных

имеет составной индекс следующим образом

ALTER TABLE [dbo].[Fact_Data] 
ADD  CONSTRAINT [PK_Fact_Data] 
PRIMARY KEY CLUSTERED 
(
    [Column1_VarChar_10] ASC,
    [Column2_VarChar_10] ASC,
    [Column3_Int] ASC,
    [Column4_Int] ASC,
    [Column5_VarChar_10] ASC,
    [Column6_VarChar_10] ASC,
    [Column7_DateTime] ASC,
    [Column8_DateTime] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON
) ON [PRIMARY]
GO

В этой структуре все столбцы varchar 10 имеют только числовые значения. Будет ли мне полезно изменить структуру из 78 миллионов строк, чтобы она содержала BIGINT вместо VARCHAR с точки зрения запросов и индексации?

Любые другие преимущества / недостатки, которые я должен рассмотреть?

Ответы [ 3 ]

14 голосов
/ 22 октября 2009

Вы должны ОПРЕДЕЛЕННО ввести суррогатный INT IDENTITY() первичный ключ !! INT уже дает вам потенциально до 2 миллиардов строк - разве этого недостаточно?

Этот первичный ключ / кластеризованный ключ на SQL Server будет иметь размер до 64 байт (вместо 4 для INT), что сделает ваш кластеризованный индекс И весь ваш некластеризованный индекс раздутым до неузнаваемости. Весь ключ кластеризации (все ваши 8 столбцов) будет включен на каждую страницу каждого некластеризованного индекса в этой таблице - тратя много и много места наверняка.

Таким образом, в любой заданной индексной таблице у вас будет в 16 раз больше записей с суррогатным ключом INT - это означает, что намного меньше операций ввода-вывода и намного меньше времени, потраченного на чтение страниц индекса.

И только представьте, что вы пытаетесь установить отношение внешнего ключа к этой таблице ... любая дочерняя таблица должна иметь все 8 столбцов вашего первичного ключа в качестве столбцов внешнего ключа и указывать все 8 колонны в каждом соединении - какой кошмар !!

При 78 миллионах строк, даже просто изменив ключ кластеризации на INT IDENTITY, вы сэкономите до 60 байт на строку, что само по себе может составить до 4 ГБ дискового пространства (и использование ОЗУ на вашем сервере). И это даже не начало подсчитывать экономию по некластеризованным индексам .......

И, конечно, да, я бы также изменил VARCHAR (10) на INT или BIGINT - если это число, сделайте тип поля числовым - нет смысла оставлять его в VARCHAR (10), действительно. Но это само по себе не будет иметь большого значения с точки зрения скорости или производительности - оно просто сделает работу с данными намного проще (не нужно всегда приводить числовые типы, например, при сравнении значений и т. Д.).

Марк

4 голосов
/ 22 октября 2009

Две вещи, которые могут повлиять на производительность индекса (и общей базы данных):

1) Размер страницы индекса 2) Скорость сравнения

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

BigInt - 8 байтов; VARCHAR может быть меньше, если размер данных невелик, поэтому он действительно зависит от ваших данных. Тем не менее, 10-символьные числа могут соответствовать типу INT SQL Server (http://msdn.microsoft.com/en-us/library/ms187745.aspx) в зависимости от размера, поэтому тип int и bigint зависит от вашего домена.

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

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

Наконец, Марк прав, что это становится очень запутанным первичным ключом. Однако, если ваши данные этого требуют - например, они являются вашими ЕДИНСТВЕННЫМИ столбцами, и вы никогда не выполняете дополнительные запросы - вы можете прекрасно сделать оптимизированную версию (с Bigints и т. Д.) Своим первичным ключом. Впрочем, отчасти пахнет кодом, поэтому я повторю его совет, чтобы действительно взглянуть на вашу модель данных и посмотреть, верна ли она.

1 голос
/ 22 октября 2009

Марк S прав в том, что 64-байтовый первичный ключ будет дублироваться в каждом индексе ЧПУ, поэтому вы будете платить стоимость ввода-вывода, которая будет влиять на объем данных, хранящихся в памяти (так как вы тратите место на странице индекса NC). Таким образом, на этом основании вопрос заключается не в том, «должен ли я конвертировать мои архивные файлы», а в том, следует ли мне рассмотреть возможность преобразования моего кластерного индекса во что-то совершенно другое.

В терминах varchar vs bigint есть веская причина для конвертации, если вы можете позволить себе время; это вне разницы в 2 байта в хранилище на поле, когда вы сравниваете значения двух разных типов, SQL будет вынужден преобразовать один из них. Это будет происходить при каждом сравнении, будь то соединение индекса или предикат в предложении where.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...