Подход подсчета к дням печати следующих 30 лет - зачем добавлять ограничение первичного ключа в подсчет? - PullRequest
0 голосов
/ 09 мая 2019

Это запрос, который я использую для распечатки всех дней в следующие 30 лет.

SELECT TOP 11000 --number of days for 30 years
       IDENTITY(INT,1,1) AS N
INTO #Tally
FROM Master.dbo.SysColumns sc1,
     Master.dbo.SysColumns sc2

declare @endDate datetime = '2049-01-01'
       ,@tmpDate datetime = '2019-01-01'

select dateadd(day, t.N - 1, @tmpDate)
from #Tally t
where t.N - 1 <= DATEDIFF(day, @tmpDate, @endDate)

Работает хорошо. Тем не менее, SQL эксперт предлагает добавить этот запрос ниже, прямо под первым разделом, где я создаю # Tally.

ALTER TABLE #Tally
ADD CONSTRAINT PK_Tally_N 
PRIMARY KEY CLUSTERED (N) WITH FILLFACTOR = 100

Если я запускаю select * from #Tally запрос «ALTER» выше, в таблице результатов нет изменений.

Интересно, с какой стати я должен добавить запрос ALTER (не смог его спросить)? Какова цель этого? Я вижу, что добавляется ограничение первичного ключа, но зачем использовать clustered(n) и fillfactor=100?

Спасибо!

Ответы [ 3 ]

2 голосов
/ 09 мая 2019

Эрай,

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

Из уст М.С. они считают это важным, когда «вероятен будущий рост индекса»:

https://docs.microsoft.com/en-us/sql/relational-databases/indexes/specify-fill-factor-for-an-index?view=sql-server-2017

Для получения дополнительной информации, пожалуйста, обращайтесь: https://www.brentozar.com/archive/2013/04/five-things-about-fillfactor/

2 голосов
/ 09 мая 2019

Лично я бы использовал другой подход к созданию таблицы учета. Я держу это как взгляд на мои системы. Это молниеносно, и вам никогда не придется беспокоиться о хранении. Эту технику я узнал от Джеффа Модена, который узнал об этом от Ицик Бен-Гана. Вы можете расширить это, чтобы иметь больше строк, если вам нужно более 10 000 штук.

create View [dbo].[cteTally] as

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )
select N from cteTally
1 голос
/ 09 мая 2019

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

 SELECT * FROM #Tally WHERE N = 858;

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

Если вы добавите указанный индекс, тот же запрос найдет N без сканирования всей таблицы и выдаст результат. Поиск в таблице будет эффективным, а созданная вами схема будет поддерживать больший параллелизм.

Теперь для предоставленного вами запроса ...

select dateadd(day, t.N - 1, @tmpDate)
from #Tally t
where t.N - 1 <= DATEDIFF(day, @tmpDate, @endDate)

SQL Server, скорее всего, все равно будет просто сканировать таблицу. Таким образом, наличие кластерного индекса на самом деле не дает вам тонны отдачи в этом случае.

У вас есть сеансовая таблица (#Tally) с одной записью на каждый день и 30-летним количеством дней. Запрос отбирает назад ... 30-летний срок. Поскольку в этом случае SQL Server должен выполнить полное сканирование, чтобы получить данные для каждой записи, я не вижу добавления индекса, дающего вам большую выгоду. Не со схемой и запросом из вашего примера.

Столбец N - хороший естественный ключ. Я не уверен, что было бы больно добавлять его, но я не думаю, что вы потеряете что-нибудь, если не сделаете. Однако, если вы начнете запрашивать подмножество значений из таблицы (а я не имею в виду весь набор записей минус один или два), кластерный индекс наверняка добавит преимущества.

Указатели состоят из страниц. Страницы могут хранить определенное количество данных. Как правило, вы хотите упаковать как можно больше данных на каждой странице. Таким образом, SQL Server не нужно сканировать слишком много страниц, чтобы найти ваши данные. Думайте о каждой странице как о ящике. Если бы в ящике было 1 предмет, для хранения 500 предметов понадобилось бы 500 ящиков. Если вы хотите найти 20 предметов, вам нужно открыть 20 ящиков. Если бы в каждом выдвижном ящике было по 100 предметов, вам нужно было бы открыть максимум 5 ящиков и хотя бы 1 ящик. Сказать FILLFACTOR equals 100 означает, что вы не оставляете места на странице (ящик); Вы наполняете это полностью. Для полей, в которых данные увеличиваются, использование коэффициента заполнения 100 является общей практикой, поскольку вы никогда не добавляете данные в середину индекса, а просто добавляете их в конец. Таким образом, вам не нужно места на существующих страницах вашего индекса для новых данных.

...