DBCC CHECKDB непоправна пошкодження: індексований вигляд містить рядки, які не були створені визначенням представлення


14

TL; DR: У індексованому вигляді у мене непоправна пошкодження. Ось деталі:


Біг

DBCC CHECKDB([DbName]) WITH EXTENDED_LOGICAL_CHECKS, DATA_PURITY, NO_INFOMSGS, ALL_ERRORMSGS

на одній з моїх баз даних виникає така помилка:

Msg 8907, рівень 16, стан 1, рядок 1 Просторовий індекс, індекс XML або індексований вигляд 'ViewName' (ідентифікатор об’єкта 784109934) містить рядки, які не були створені визначенням представлення. Це не обов'язково означає проблему цілісності даних у цій базі даних. (...)

CHECKDB знайшов 0 помилок розподілу та 1 помилку узгодженості у таблиці "ViewName".

repair_rebuild - мінімальний рівень ремонту (...).

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

SELECT * FROM ViewName WITH (NOEXPAND)
EXCEPT
SELECT ...
from T1 WITH (FORCESCAN)
join T2 on ...

SELECT ...
from T1 WITH (FORCESCAN)
join T2 on ...
EXCEPT
SELECT * FROM ViewName WITH (NOEXPAND)

NOEXPANDбуло використано для примусового використання (тільки) індексу на ViewName. FORCESCANвикористовувався для запобігання відповідності індексованого перегляду. План виконання підтверджує, що обидва заходи працюють.

Тут не повертаються рядки, це означає, що дві таблиці однакові. (Є лише цілі чи стовпчики з цілими та наведеннями, порівняння не вступають у дію).

Помилку неможливо виправити , відтворивши індекс у вікні перегляду чи запустивши DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS. Повторення виправлень також не допомогло. Чому DBCC CHECKDBповідомляється про цю помилку? Як позбутися від цього?

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


Оновлення: помилка була виправлена ​​в деяких випусках. Я більше не може відтворити його в SQL Server 2014 з пакетом оновлень 2 CU 5. 2014 SP2 KB містить виправлення без KB статті: Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error. Два помилки з цього приводу були закриті:


1
Ви хочете сказати, що ви скинули та знову створили індекс для представлення даних, а DBCC CHECKDB все ще повідомляє ту саму помилку? А як щодо того, щоб скинути погляд і створити його з нуля?
Аарон Бертран

З BOL: Усунення помилок DBCC в індексованих переглядах If the indexed view does not contain an aggregate over values of type float or real and you receive errors 8907 or 8708, drop the index on the view and re-create it. Do not use ALTER INDEX REBUILD to try to remove the differences between the stored and the computed view, because ALTER INDEX REBUILD does not recalculate the view before rebuilding the index. Then run DBCC CHECKTABLE on the View to verify no differences remain.
Кін Шах

@Kin Я відредагував ваш коментар. [1]Нотація не працює в зауваженні націнці вниз.
Аарон Бертран

Я все відтворив. Я також дозволяю DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS запускатися. Він сказав, що відновив вигляд, але потім повідомив про ту саму помилку.
usr

Чи можете ви показати визначення перегляду (якщо занадто довго тут, то в пасті)?
Аарон Бертран

Відповіді:


14

Процесор запитів може створити недійсний план виконання для (правильного) запиту, згенерованого DBCC, щоб перевірити, що індекс перегляду видає ті самі рядки, що і базовий запит перегляду.

План виробництва процесора запиту неправильно обробляє NULLsдля ImageObjectIDстовпця. Це неправильно мотивує те, що запит перегляду відхиляє NULLsцей стовпець, коли цього немає. Думаючи, що NULLsце виключено, він може співставити відфільтрований некластеризований індекс на Usersтаблиці, за якою фільтрується ImageObjectID IS NOT NULL.

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

Визначення перегляду:

SELECT
    dbo.Universities.ID AS Universities_ID, 
    dbo.Users.ImageObjectID AS Users_ImageObjectID
FROM dbo.Universities
JOIN dbo.Users
    ON dbo.Universities.AdminUserID = dbo.Users.ID

ONПорівняння положення рівності між AdminUserIDі IDпокидьками NULLsв цих колонках, але не з ImageObjectIDколонки.

Частиною запиту, створеного DBCC, є:

SELECT [Universities_ID], [Users_ImageObjectID], 0 as 'SOURCE'
FROM [dbo].[mv_Universities_Users_ID] tOuter WITH (NOEXPAND) 
WHERE NOT EXISTS
( 
    SELECT 1 
    FROM   [dbo].[mv_Universities_Users_ID] tInner
    WHERE 
    (
        (
            (
                [tInner].[Universities_ID] = [tOuter].[Universities_ID]
            ) 
            OR 
            (
                [tInner].[Universities_ID] IS NULL
                AND [tOuter].[Universities_ID] IS NULL
            )
        )
        AND
        (
            (
                [tInner].[Users_ImageObjectID] = [tOuter].[Users_ImageObjectID]
            ) 
            OR 
            (
                [tInner].[Users_ImageObjectID] IS NULL 
                AND [tOuter].[Users_ImageObjectID] IS NULL
            )
        )
    )
)
OPTION (EXPAND VIEWS);

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

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

Помилковий план

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

Основний шлях коду оптимізатора (для запитів користувачів) не містить цієї помилки, тому він специфічний для внутрішніх запитів, таких як генеровані DBCC.


Я бачу несправний план у події SQL Profiler Showplan XML. Я позначу це як відповідь; Чому DBCC будує запит інакше, ніж звичайний процесор запитів ?; Я додам посилання на цю відповідь до елемента підключення.
usr

2
@usr DBCC робить усілякі речі, які неможливо було б підключити до користувача. Я думаю, що це працює так, тому що це потрібно, але вам доведеться попросити когось, як Пол Рандал, щоб дізнатись про цю деталь. Він, звичайно, не може вільно сказати. Я знаю, що поза DBCC є багато речей, які роблять навіть більш дивні речі; деякі навіть будують план виконання, навіть не проходячи оптимізатор!
Пол Білий 9

6

Подальше дослідження показує, що це помилка в DBCC CHECKDB. Було відкрито помилку Microsoft Connect: Несправна помилка DBCC CHECKDB (що також є помилковим позитивом та інакше дивним) . На щастя, мені вдалося створити запит, щоб помилку можна було знайти та виправити.

Помилку можна приховати, граючи зі схемою бази даних. Видалення непов'язаного відфільтрованого індексу або видалення фільтра приховує помилку. Докладніше див. Елемент підключення.

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

Помилка була виправлена ​​в деяких випусках. Я більше не можу його відтворити в SQL Server 2014 SP2 CU 5.


Для відтворення помилки було потрібно багато (виробничих) даних (що є додатковим свідченням того, що причиною може бути зміна плану). Мені не зручно випускати дані, хоча мені вдалося видалити всі, крім двох стовпців, з кожної таблиці. Проблема, з якою ви пов’язали, вимагає корупції у представленні. Я відтворив думку, тому жодна корупція через DML не може бути причиною; Чи знаєте ви про все, що може спричинити інший план, якщо запит виконується під DBCC CHECKDB замість звичайного вікна запиту?
usr

Щойно завантажено анонімізовану базу даних. Ось сценарій, який відновлює всі індекси та відтворює представлення: pastebin.com/jPEALeEw (корисно скинути все та переконатися, що фізична структура нормальна). Інші корисні сценарії: pastebin.com/KxNSwm2J Сценарії потрібно просто запустити, і проблему слід негайно повторити.
usr

Дзеркало .bak
usr

11.0.3349 з -T272,4199,3604. 4199 увімкнено виправлення процесора запитів. Я щойно видалив цю ТФ; Можливо, нам потрібно скласти правильний план запитів. Тепер я встановив 1 Гб оперативної пам’яті і перезапустив примірник (був 8 ГБ). Це змінило одне з двох об'єднань, які я бачив у NLJ. Досі докори; Щоб спробувати кілька варіантів плану, я додав і видалив рядки: pastebin.com/y972Sx4d Помилка, здається, запускає iff, я отримую об'єднання об'єднань або хеш у частині запиту "лівий антиполовин". Спробуйте це: додайте 100k рядків для користувачів. Це надійно дає (паралельне) хеш-з'єднання для мене.
usr

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