DBCC CHECKDB korupsi yang tidak dapat diperbaiki: Tampilan indeks berisi baris yang tidak diproduksi oleh definisi tampilan

14

TL; DR: Saya mengalami korupsi yang tidak dapat diperbaiki dalam tampilan yang diindeks. Berikut detailnya:


Lari

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

di salah satu database saya menghasilkan kesalahan berikut:

Msg 8907, Level 16, State 1, Line 1 Indeks spasial, indeks XML atau tampilan terindeks 'ViewName' (objek ID 784109934) berisi baris yang tidak diproduksi oleh definisi tampilan. Ini tidak selalu mewakili masalah integritas dengan data dalam database ini. (...)

CHECKDB menemukan 0 kesalahan alokasi dan 1 kesalahan konsistensi pada tabel 'ViewName'.

repair_rebuild adalah level perbaikan minimum (...).

Saya mengerti bahwa pesan ini menunjukkan bahwa data material dari tampilan yang diindeks 'ViewName' tidak identik dengan apa yang dihasilkan oleh kueri yang mendasarinya. Namun, memverifikasi data secara manual tidak menimbulkan perbedaan apa pun:

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)

NOEXPANDdigunakan untuk memaksa penggunaan indeks (hanya) pada ViewName. FORCESCANdigunakan untuk mencegah pencocokan tampilan indeks. Rencana pelaksanaan mengkonfirmasi kedua langkah tersebut berfungsi.

Tidak ada baris yang dikembalikan di sini, artinya kedua tabel identik. (Hanya ada kolom integer dan guid, collations tidak ikut bermain).

Kesalahan tidak dapat diperbaiki dengan membuat ulang indeks pada tampilan atau dengan menjalankan DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS. Mengulangi perbaikan juga tidak membantu. Mengapa DBCC CHECKDBmelaporkan kesalahan ini? Bagaimana cara menghilangkannya?

(Bahkan jika pembangunan kembali memperbaikinya, pertanyaan saya akan tetap berlaku - mengapa kesalahan dilaporkan meskipun kueri pemeriksaan data saya berhasil?)


Pembaruan: Bug telah diperbaiki dalam beberapa rilis. Aku tidak bisa lagi mereproduksi dalam SQL Server 2014 SP2 CU 5. 2014 SP2 KB mengandung memperbaiki tanpa artikel KB: Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error. Dua bug koneksi tentang ini telah ditutup:

usr
sumber
1
Apakah Anda mengatakan Anda menjatuhkan dan membuat kembali indeks pada tampilan dan DBCC CHECKDB masih melaporkan kesalahan yang sama? Bagaimana dengan menjatuhkan tampilan dan membuatnya dari awal?
Aaron Bertrand
Dari BOL: Memecahkan Masalah Kesalahan DBCC pada Tampilan yang Diindeks 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, saya mengedit komentar Anda. The [1]notasi tidak bekerja dalam komentar mark-down.
Aaron Bertrand
Saya menciptakan kembali semuanya. Saya juga membiarkan DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS berjalan. Dikatakan itu membangun kembali pandangan, tetapi kemudian melaporkan kesalahan yang sama.
usr
Bisakah Anda menunjukkan definisi tampilan (jika terlalu lama di sini lalu di pastebin)?
Aaron Bertrand

Jawaban:

14

Prosesor permintaan dapat menghasilkan rencana pelaksanaan yang tidak valid untuk permintaan (benar) yang dihasilkan oleh DBCC untuk memeriksa bahwa indeks tampilan menghasilkan baris yang sama dengan permintaan tampilan yang mendasarinya.

Rencana yang dihasilkan oleh prosesor query salah menangani NULLsuntuk ImageObjectIDkolom. Itu salah alasan permintaan tampilan menolak NULLsuntuk kolom ini, padahal tidak. Berpikir yang NULLsdikecualikan, itu dapat mencocokkan indeks nonclustered disaring pada Userstabel yang difilter ImageObjectID IS NOT NULL.

Dengan menghasilkan rencana yang menggunakan indeks yang difilter ini, memastikan bahwa baris dengan NULLin ImageObjectIDtidak ditemui. Baris-baris ini dikembalikan (dengan benar) dari indeks tampilan, jadi sepertinya ada korupsi saat tidak ada.

Definisi tampilan adalah:

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

The ONklausul kesetaraan perbandingan antara AdminUserIDdan IDmenolak NULLsdi kolom tersebut, tetapi bukan dari ImageObjectIDkolom.

Bagian dari permintaan yang dihasilkan DBCC adalah:

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

Ini adalah kode umum yang membandingkan nilai-nilai secara NULLsadar. Ini memang verbose, tetapi logikanya baik-baik saja.

Bug dalam penalaran prosesor kueri berarti bahwa rencana kueri yang salah menggunakan indeks yang difilter dapat dihasilkan, seperti dalam contoh fragmen paket di bawah ini:

Rencana salah

Permintaan DBCC mengambil jalur kode yang berbeda melalui prosesor permintaan dari permintaan pengguna. Jalur kode ini berisi bug. Ketika sebuah rencana menggunakan indeks yang difilter dihasilkan, itu tidak dapat digunakan dengan USE PLANpetunjuk untuk memaksa bentuk rencana itu dengan teks kueri yang sama yang dikirimkan dari koneksi database pengguna.

Jalur kode pengoptimal utama (untuk kueri pengguna) tidak mengandung bug ini, jadi khusus untuk kueri internal seperti yang dihasilkan oleh DBCC.

Paul White 9
sumber
Saya bisa melihat rencana yang salah dalam acara XML Profiler Showplan XML. Saya akan menandai ini sebagai jawabannya .; Mengapa DBCC membuat kueri dengan cara yang berbeda dari prosesor kueri normal ?; Saya akan menambahkan tautan ke jawaban ini ke item sambungkan.
usr
2
@ usr DBCC melakukan segala macam hal yang tidak mungkin dilakukan dari koneksi pengguna. Saya membayangkan itu bekerja seperti ini karena memang harus, tetapi Anda harus meminta seseorang seperti Paul Randal untuk mendapatkan detail yang sebenarnya tentang itu. Dia mungkin tidak berhak mengatakannya, tentu saja. Saya tahu bahwa ada banyak hal di luar DBCC yang bahkan lebih aneh; beberapa bahkan membuat rencana eksekusi tanpa melalui pengoptimal sama sekali!
Paul White 9
6

Investigasi lebih lanjut menunjukkan bahwa ini adalah bug dalam DBCC CHECKDB. Bug Microsoft Connect telah dibuka: Kesalahan DBCC CHECKDB yang tidak dapat diperbaiki (itu juga merupakan false positive dan sebaliknya aneh) . Untungnya, saya bisa menghasilkan repro sehingga bug dapat ditemukan dan diperbaiki.

Bug dapat disembunyikan dengan bermain dengan skema database. Menghapus indeks terfilter yang tidak terkait, atau menghapus filter, menyembunyikan bug. Untuk detailnya, silakan lihat item terhubung.

Item terhubung juga berisi permintaan internal yang digunakan DBCC CHECKDB untuk memvalidasi konten tampilan. Itu tidak mengembalikan hasil, menunjukkan bahwa ini adalah bug.

Bug telah diperbaiki dalam beberapa rilis. Saya tidak bisa lagi mereproduksi di SQL Server 2014 SP2 CU 5.

usr
sumber
Banyak data (produksi) diperlukan untuk mereproduksi bug (yang merupakan bukti lebih lanjut bahwa perubahan rencana mungkin menjadi penyebabnya). Saya tidak nyaman merilis data meskipun saya bisa menghapus semua kecuali dua kolom dari setiap tabel. Masalah yang Anda tautkan mengharuskan korupsi di tampilan. Saya membuat ulang tampilan sehingga tidak ada korupsi karena DML dapat menjadi penyebabnya; Apakah Anda mengetahui sesuatu yang dapat menyebabkan rencana berbeda jika kueri dijalankan di bawah DBCC CHECKDB alih-alih di jendela kueri normal?
usr
Basis data anonim baru saja diunggah. Berikut ini adalah skrip yang membangun kembali semua indeks dan membuat ulang tampilan: pastebin.com/jPEALeEw (berguna untuk mengatur ulang semuanya dan memastikan struktur fisiknya ok). Skrip bermanfaat lainnya: pastebin.com/KxNSwm2J Skrip harus dijalankan dan masalah harus segera ditegur ulang.
usr
Cermin .bak: mega.co.nz/…
usr
Pada 11.0.3349 dengan -T272,4199.3604. 4199 perbaikan prosesor permintaan diaktifkan. Saya baru saja menghapus TF itu; Mungkin kita perlu menginduksi rencana permintaan yang tepat. Saya sekarang telah menetapkan 1GB RAM dan memulai kembali instance (adalah 8GB). Itu mengubah salah satu dari dua gabungan bergabung yang saya lihat ke NLJ. Masih repros; Untuk mencoba beberapa variasi paket, saya menambahkan dan menghapus baris: pastebin.com/y972Sx4d Bug ini tampaknya memicu iff saya mendapatkan gabungan gabung atau hash di bagian "kiri anti semi bergabung" dari kueri. Coba ini: tambahkan 100 ribu baris ke Pengguna. Ini andal memberikan hash (paralel) bergabung untuk saya.
usr
Saya baru saja mengunggah "plan.zip" ke item terhubung yang berisi berbagai paket eksekusi untuk permintaan DBCC CHECKDB. Dengan jumlah baris berbeda di Universitas, saya dapat menghasilkan setidaknya tiga rencana berbeda. Hanya dengan rencana loop bergabung masalah tidak terjadi. Dengan penggabungan dan hash bergabung, bug dapat direproduksi.
usr