DBCC CHECKDB düzeltilemeyen bozulma: Dizinlenmiş görünüm, görünüm tanımı tarafından oluşturulmayan satırlar içeriyor


14

TL; DR: Dizinlenmiş görünümde düzeltilemez bir yolsuzluk var. İşte detaylar:


Koşu

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

veritabanlarımdan birinde aşağıdaki hata oluşuyor:

Msg 8907, Seviye 16, Durum 1, Satır 1 Uzamsal dizin, XML dizini veya dizinlenmiş görünüm 'ViewName' (nesne kimliği 784109934), görünüm tanımı tarafından üretilmeyen satırlar içeriyor. Bu, bu veritabanındaki verilerle bir bütünlük sorununu göstermez. (...)

CHECKDB 'ViewName' tablosunda 0 ayırma hatası ve 1 tutarlılık hatası buldu.

repair_rebuild minimum onarım düzeyidir (...).

Bu iletinin dizinlenmiş görünüm 'ViewName' malzeme verilerinin temel sorgunun ürettiği ile aynı olmadığını gösterdiğini anlıyorum. Ancak, verilerin manuel olarak doğrulanması herhangi bir tutarsızlığa neden olmaz:

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(yalnızca) dizininin kullanılmasını zorlamak için kullanıldı ViewName. FORCESCANdizine alınmış görünüm eşleşmesinin olmasını önlemek için kullanıldı. Uygulama planı her iki tedbirin de işe yaradığını teyit eder.

Burada hiçbir satır döndürülmez, yani iki tablo aynıdır. (Yalnızca tamsayı ve kılavuz sütunlar vardır, harmanlamalar devreye girmez).

Hata , dizini görünümde yeniden oluşturarak veya çalıştırarak düzeltilemezDBCC CHECKDB REPAIR_ALLOW_DATA_LOSS . Düzeltmeleri tekrarlamak da yardımcı olmadı. Bu hatayı neden DBCC CHECKDBbildiriyor? Nasıl kurtulur?

(Yeniden oluşturma sorunu düzeltilse bile sorum hala geçerli olacak - veri kontrol sorgularım başarıyla çalışmasına rağmen neden bir hata bildiriliyor?)


Güncelleme: Bazı sürümlerde hata giderildi. Artık 2014 SP2 CU 5. SQL Server üretebileceği 2014 SP2 KB KB makalesinde olmadan bir düzeltme içerir: Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error. Bununla ilgili iki bağlantı hatası kapatıldı:


1
Görünümde dizini bırakıp yeniden oluşturduğunuzu mu söylüyorsunuz ve DBCC CHECKDB hala aynı hatayı rapor ediyor mu? Görünümü bırakıp sıfırdan oluşturmaya ne dersiniz?
Aaron Bertrand

From BOL: Dizinli Görünümlerde DBCC Hataları Sorun Giderme 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 Shah

@Kin Yorumunuzu düzenledim. [1]Notasyonu comment işareti aşağı çalışmaz.
Aaron Bertrand

Her şeyi yeniden yarattım. Ayrıca DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS çalışmasına izin verdim. Görünümü yeniden oluşturduğunu söyledi, ancak daha sonra aynı hatayı bildirdi.
usr

Görünüm tanımını gösterebilir misiniz (eğer burada çok uzunsa o zaman bir çöp kovasında)?
Aaron Bertrand

Yanıtlar:


14

Sorgu işlemcisi, görünüm dizininin temeldeki görünüm sorgusu ile aynı satırları ürettiğini denetlemek için DBCC tarafından oluşturulan (doğru) sorgu için geçersiz bir yürütme planı oluşturabilir.

Sorgu işlemcisi tarafından üretilen plan NULLs, ImageObjectIDsütunu yanlış işliyor . Yanlışlıkla, görünüm sorgusu NULLsbu sütun için reddetmek neden olur. NULLsDışlananları düşünerek , filtrelenen Userstablodaki filtrelenmemiş kümelenmemiş dizinle eşleşebilir ImageObjectID IS NOT NULL.

Bu filtrelenmiş dizini kullanan bir plan oluşturarak, NULLiçindeki satırlarla ImageObjectIDkarşılaşılmamasını sağlar. Bu satırlar görünüm dizininden (doğru olarak) döndürülür, bu nedenle olmadığında bir bozulma olduğu görülür.

Görünüm tanımı:

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

Bu sütunlar ONarasındaki cümle eşitliği karşılaştırması AdminUserIDve bu sütunlarda IDreddedilir NULLs, ancak ImageObjectIDsütundan değil .

DBCC tarafından oluşturulan sorgunun bir kısmı:

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);

Bu, değerleri NULL-aware biçiminde karşılaştıran genel koddur . Kesinlikle ayrıntılı, ama mantık iyi.

Sorgu işlemcisinin gerekçesindeki hata, aşağıdaki örnek plan parçasında olduğu gibi, filtrelenmiş dizini yanlış kullanan bir sorgu planının üretilebileceği anlamına gelir:

Hatalı plan

DBCC sorgusu, sorgu işlemcisi aracılığıyla kullanıcı sorgularından farklı bir kod yolu alır. Bu kod yolu hatayı içerir. Filtrelenmiş dizini kullanan bir plan oluşturulduğunda, bu USE PLANplan şeklini bir kullanıcı veritabanı bağlantısından gönderilen aynı sorgu metni ile zorlamak için ipucu ile kullanılamaz .

Ana iyileştirici kod yolu (kullanıcı sorguları için) bu hatayı içermediğinden DBCC tarafından oluşturulanlar gibi dahili sorgulara özgüdür.


SQL Profiler Showplan XML olayında hatalı planı görebilirsiniz. Bunu cevap olarak işaretleyeceğim .; DBCC sorguyu neden normal sorgu işlemcisinden farklı bir şekilde oluşturuyor ?; Bu cevaba bağlantı öğesine bir bağlantı ekleyeceğim.
usr

2
@usr DBCC, kullanıcı bağlantısından mümkün olmayan her şeyi yapar. Bunun böyle çalıştığını hayal ediyorum çünkü gerekiyor, ama Paul Randal gibi birinden bununla ilgili gerçek ayrıntıyı almasını istemelisin. Tabii ki söyleme özgürlüğü olmayabilir. DBCC dışında garip şeyler yapan birçok şey olduğunu biliyorum; hatta bazıları optimize ediciden geçmeden bir uygulama planı hazırlar!
Paul White 9

6

Daha fazla araştırma, bunun DBCC CHECKDB'de bir hata olduğunu göstermektedir. Bir Microsoft Connect hatası açıldı: Düzeltilemez DBCC CHECKDB hatası (bu aynı zamanda yanlış pozitif ve tuhaftır) . Neyse ki, hatanın bulunabilmesi ve düzeltilebilmesi için bir repro üretebildim.

Hata, veritabanı şeması ile oynatılarak gizlenebilir. İlişkisiz filtrelenmiş bir dizini silmek veya filtreyi kaldırmak hatayı gizler. Ayrıntılar için lütfen bağlantı öğesine bakın.

Bağlantı öğesi ayrıca DBCC CHECKDB'nin görünüm içeriğini doğrulamak için kullandığı dahili sorguyu içerir. Bunun bir hata olduğunu gösteren hiçbir sonuç döndürmez.

Hata bazı sürümlerde düzeltildi. Artık SQL Server 2014 SP2 CU 5'te yeniden üretemiyorum.


Hatayı yeniden üretmek için çok sayıda (üretim) veri gerekiyordu (bu da plan değişikliğinin neden olabileceğine dair daha fazla kanıt). Her tablodan iki sütun hariç tüm sütunları silebildiğim halde verileri serbest bırakmakta rahat değilim. Bağlantı kurduğunuz sorun, görünümde bozulmaya neden olmayı gerektiriyor. Nedeni DML nedeniyle herhangi bir yolsuzluk olmaması için yeniden yarattım .; Sorgu normal bir sorgu penceresi yerine DBCC CHECKDB altında çalıştırılıyorsa, farklı bir plana neden olabilecek herhangi bir şeyin farkında mısınız?
usr

Anonimleştirilmiş bir veritabanı henüz yüklendi. İşte tüm dizinleri yeniden oluşturan ve görünümü yeniden oluşturan bir komut dosyası: pastebin.com/jPEALeEw (her şeyi sıfırlamak ve fiziksel yapının iyi olduğundan emin olmak için yararlıdır). Diğer yararlı komut dosyaları: pastebin.com/KxNSwm2J Komut dosyaları çalışmalı ve sorun hemen yeniden oluşturulmalıdır.
usr


11.0.3349 tarihinde -T272.4199.3604 ile. 4199 etkin sorgu işlemci düzeltmeleri. TF'yi yeni çıkardım .; Belki de doğru sorgu planını başlatmamız gerekir. Şimdi 1GB RAM ayarladım ve örneği yeniden başlattım (8GB). Bu, gördüğüm iki birleştirme birleşimlerinden birini NLJ olarak değiştirdi. Hala repros .; Bazı plan varyasyonlarını denemek için satırları ekledim ve kaldırdım: pastebin.com/y972Sx4d Hata, sorgunun "sol anti yarı birleştirme" bölümünde bir birleştirme birleşimi veya karma aldığımı tetikliyor gibi görünüyor. Bunu deneyin: Kullanıcılara 100 bin satır ekleyin. Bu benim için güvenilir bir (paralel) karma birleşimi sağlar.
usr

DBCC CHECKDB sorgusu için farklı yürütme planları içeren bağlantı öğesine "plans.zip" dosyasını yükledim. Üniversitelerdeki farklı satır sayımları ile en az üç farklı plan oluşturabilirim. Sadece döngü birleşimleri planı ile sorun oluşmaz. Birleştirme ve karma birleştirmelerle hata yeniden üretilebilir.
usr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.