Чому після збільшення розміру стовпця потрібно більше часу створювати індекс?


18

Наш постачальник змінив ширину стовпців майже на кожному стовпчику всієї бази даних. База даних становить близько 7 ТБ, 9000+ таблиць. Ми намагаємось створити індекс на таблиці, яка містить 5,5 мільярдів рядків. Перед оновленням постачальника ми могли створити індекс за 2 години. Зараз це займає дні. Що вони зробили, це збільшити розмір будь-якого варшара (xx) до varchar (256). Тож більшість стовпців використовувались як варчар (18) або варчар (75) тощо.

У будь-якому разі первинний ключ складається з 6 стовпців, ширина яких склала 126 символів. Тепер після оновлення первинним ключем є 1283 символи, що порушує ліміт серверів SQL в 900 символів. Вся ширина стовпця таблиці перейшла від загального комбінованого числа варчарів 1049 до загального комбінованого числа варчарів 4009.

Дані не збільшуються, таблиця не займає більше "простору", ніж раніше, ніж все ширина стовпця збільшувалася, але продуктивність для створення чогось такого простого, як індекс зараз займає необгрунтовану кількість часу.

Чи може хтось пояснити, чому на створення та індексацію потрібно стільки часу, коли єдине, що було зроблено - це збільшити розмір стовпців?

Індекс, який ми намагаємося створити, не є кластером, оскільки pk - це кластерний індекс. Після кількох спроб створити індекс, ми здалися. Я думаю, що пройшло 4 або 5 днів без завершення.

Я спробував це в невиробничому середовищі, зробивши знімок файлової системи та вивів базу даних на більш тихий сервер.

Відповіді:


12

Ремус корисно вказав, що максимальна довжина VARCHARстовпця впливає на передбачуваний розмір рядка і тому надає пам'ять, яку надає SQL Server.

Я спробував зробити трохи більше досліджень, щоб розширити частину своєї відповіді на "від цього на каскад речей". У мене немає повного чи стислого пояснення, але ось що я знайшов.

Repro скрипт

Я створив повний сценарій, який генерує підроблений набір даних, на якому створення індексу займає приблизно 10 разів більше часу на моїй машині для VARCHAR(256)версії. Дані , що використовуються в точності те ж саме, але перша таблиця використовує фактичні максимальні довжини 18, 75, 9, 15, 123, і 5, в той час як всі стовпці використовувати максимальну довжину 256в другій таблиці.


Збереження оригінальної таблиці

Тут ми бачимо, що початковий запит завершується приблизно за 20 секунд, а логічні зчитування дорівнюють розміру таблиці ~1.5GB(195 К сторінок, 8 К на сторінку).

-- CPU time = 37674 ms,  elapsed time = 19206 ms.
-- Table 'testVarchar'. Scan count 9, logical reads 194490, physical reads 0
CREATE CLUSTERED INDEX IX_testVarchar
ON dbo.testVarchar (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO


Клавіша таблиці VARCHAR (256)

З VARCHAR(256)таблиці ми бачимо, що минулий час різко збільшився.

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

-- CPU time = 33212 ms,  elapsed time = 263134 ms.
-- Table 'testVarchar256'. Scan count 9, logical reads 194491
CREATE CLUSTERED INDEX IX_testVarchar256
ON dbo.testVarchar256 (s1, s2, s3, s4)
WITH (MAXDOP = 8) -- Same as my global MAXDOP, but just being explicit
GO


Статистика вводу / виводу та очікування: оригінал

Якщо ми захопимо трохи детальніше (використовуючи p_perfMon, процедуру, яку я написав ), ми можемо побачити, що переважна більшість вводу-виводу виконується у LOGфайлі. Ми бачимо відносно скромну кількість вводу-виводу на фактичну ROWS(основний файл даних), і основним типом очікування є LATCH_EX, що вказує на вміст сторінки в пам'яті.

Ми також можемо побачити, що мій спінінг знаходиться десь між "поганим" і "шокуюче поганим", за словами Пола Рандала :)

введіть тут опис зображення


Статистика вводу / виводу та очікування: VARCHAR (256)

Для VARCHAR(256)версії статистика вводу / виводу та очікування виглядає зовсім інакше! Тут ми бачимо величезне збільшення вводу-виводу на файл даних ( ROWS), а час перерви тепер змушує Пола Рандала просто сказати "WOW!".

Не дивно, що зараз номер 1 очікування IO_COMPLETION. Але чому генерується стільки вводу-виводу?

введіть тут опис зображення


Фактичний план запитів: VARCHAR (256)

З плану запитів ми бачимо, що Sortоператор має рекурсивний розлив (глибиною 5 рівнів!) У VARCHAR(256)версії запиту. (У початковій версії взагалі немає розливу.)

введіть тут опис зображення


Хід запиту наживо: VARCHAR (256)

Ми можемо використовувати sys.dm_exec_query_profiles для перегляду ходу запитів у реальному часі в SQL 2014+ . У оригінальній версії цілі Table Scanта Sortобробляються без будь-яких розливів ( spill_page_countзалишається на 0всьому протязі).

У VARCHAR(256)версії, однак, ми бачимо, що розливи сторінок швидко накопичуються для Sortоператора. Ось короткий знімок ходу запиту безпосередньо перед завершенням запиту. Дані тут агрегуються у всіх потоках.

введіть тут опис зображення

Якщо я викопаю кожну нитку окремо, я бачу, що 2 потоки завершують сортування протягом приблизно 5 секунд (загалом @ 20 секунд, після 15 секунд, витрачених на сканування таблиці). Якби всі потоки прогресували з такою швидкістю, VARCHAR(256)створення індексу завершилося б приблизно за той самий час, що і початкова таблиця.

Однак решта 6 ниток просуваються значно повільніше. Це може бути пов’язано із способом розподілу пам'яті та способом, яким нитки утримуються введенням-виведенням під час їх розсипання даних. Я точно не знаю, хоча.

введіть тут опис зображення


Що ти можеш зробити?

Є кілька речей, які ви можете розглянути:

  • Попрацюйте з постачальником, щоб повернутись до попередньої версії. Якщо це неможливо, дозвольте постачальнику, що ви не задоволені цією зміною, щоб вони могли розглянути можливість його повернення у майбутньому випуску.
  • Додаючи свій індекс, подумайте про те, OPTION (MAXDOP X)де Xвикористовувати менший номер, ніж ваш поточний параметр на рівні сервера. Коли я використовував OPTION (MAXDOP 2)цей специфічний набір даних на своїй машині, VARCHAR(256)версія завершилася 25 seconds(порівняно з 3-4 хвилинами з 8 нитками!). Можливо, що поведінка розливу посилюється вищим паралелізмом.
  • Якщо додаткові інвестиції в обладнання - це можливість, профіліруйте введення / виведення (ймовірне вузьке місце) у вашій системі та обміркуйте використання SSD для зменшення затримки вводу / виводу, спричиненого розливом.


Подальше читання

У Пола Уайта є приємна публікація в блозі про внутрішні види SQL Server, які можуть зацікавити. Це трохи розповідає про розливання, перекручування потоку та розподіл пам'яті для паралельних сортів.


11

Таблиця проміжного сортування буде по-різному оцінена між двома випадками. Це призведе до різних запитів на отримання пам’яті ( VARCHAR(256)буде більше) і, ймовірно, набагато меншим фактичним грант, відсотково розумним, порівняно з «ідеальним» запитом. Я думаю, це призводить до розливу під час сортування.

Тестуючи сценарій від Geoff (лише в 100k рядків), я чітко бачу різницю в орієнтованому розмірі рядків (141B проти 789B). З цього на речі каскад.


8
Я впевнений, що Пол докаже більш ретельну і повну відповідь, включаючи, можливо, стеки дзвінків, які будуть використані як навчальний матеріал командою розробників. Знову ...
Ремус Русану
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.