Швидко змініть стовпчик NULL на NOT NULL


11

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

ALTER TABLE MyTable ALTER COLUMN MyColumn BIGINT NOT NULL;

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


2
Ні (або принаймні не використовуються документально підтверджені / підтримувані методи). Див. Чому ALTER COLUMN TO NOT NULL викликає масовий ріст файлів журналу?
Мартін Сміт

2
Можливо, він також може чекати Sch-Mблокування, коли це займе "назавжди". Ви подивилися, чи чекає він чи зайнятий?
Мартін Сміт

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

Відповіді:


12

@ ypercube відповідь частково керує цією зміною лише метадані.

Додавання обмеження NOCHECKозначає, що для його перевірки не потрібно читати жодних рядків, і якщо ви починаєте з позиції, коли стовпець не містить NULLзначень (і якщо ви знаєте, жодного не буде додано між перевіркою та додаванням обмеження), оскільки обмеження не дозволяє NULLстворювати значення з майбутніх INSERTчи UPDATEоперацій, це буде спрацьовувати.

Додавання обмеження все ще може впливати на одночасні транзакції. ALTER TABLEПотрібно буде придбати Sch-Mзамок першим. Поки він чекає цього, всі інші доступу до таблиці будуть заблоковані, як описано тут .

Після Sch-Mпридбання блокування операція повинна бути досить швидкою.

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

CREATE TABLE T (X INT NULL)

INSERT INTO T 
SELECT ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM master..spt_values

ALTER TABLE T WITH NOCHECK
  ADD  CONSTRAINT X_NOT_NULL 
    CHECK (X IS NOT NULL) ; 

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

План

Порівняйте це з більш простим

ALTER TABLE T ALTER COLUMN X INT NOT NULL

SELECT *
FROM T 
WHERE X NOT IN (SELECT X FROM T)

План

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

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


7

Ви можете замість зміни стовпця додати CHECKобмеження таблиці за допомогою NOCHECKпараметра:

ALTER TABLE MyTable WITH NOCHECK
  ADD  CONSTRAINT MyColumn_NOT_NULL 
    CHECK (MyColumn IS NOT NULL) ;

1
Це дозволить уникнути майбутніх оновлень або вставок, які створюють стовпець, NULLале вони не зможуть використовуватись оптимізатором запитів.
Мартін Сміт

@MartinSmith О так, я просто прочитав відповідь та коментарі у подібному питанні: Як додати стовпець NOT NULL до великої таблиці на SQL Server? Будь ласка, додайте відповідь на проблеми або краще рішення, і я видалю свою.
ypercubeᵀᴹ

2
У мене немає кращого рішення. Я підтримав це, оскільки це забезпечує часткове рішення. Якщо все, що хоче зробити, це запобігти недійсним даним, воно буде працювати (і має бути швидше, ніж ALTER COLUMNколись Sch-Mзамок отриманий, для цього не потрібно сканувати рядки взагалі). Тільки зазначивши, що це не зовсім те саме (наприклад, якщо використовується в NOT INзапиті, план буде складнішим)
Martin Smith
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.