Apa arsitektur indeks yang sesuai ketika dipaksa untuk mengimplementasikan IsDeleted (penghapusan lunak)?

16

Saat ini, kami memiliki database dan aplikasi yang sudah ada yang berfungsi penuh. Saya tidak memiliki kemampuan untuk mengubah arsitektur pada saat ini. Hari ini, setiap tabel dalam database memiliki bidang "IsDeleted" BUKAN NULL BIT dengan default '0'. Ketika aplikasi "menghapus" data, itu hanya memperbarui bendera IsDeleted ke 1.

Yang saya mengalami kesulitan memahami adalah bagaimana indeks pada masing-masing tabel harus disusun. Saat ini, setiap query / join / etc selalu mengimplementasikan pemeriksaan IsDeleted. Ini adalah standar yang harus diikuti oleh pengembang kami. Yang sedang berkata, saya mencoba untuk menentukan apakah semua indeks kunci utama berkerumun saya pada setiap tabel perlu diubah untuk memasukkan kunci utama DAN bidang BIT IsDeleted. Juga, karena SETIAP permintaan / gabung / dll. harus menerapkan pemeriksaan IsDeleted, apakah ini asumsi yang tepat bahwa indeks SETIAP TUNGGAL (non-clustered juga) harus menyertakan bidang IsDeleted sebagai bidang pertama indeks?

Satu pertanyaan lain yang saya miliki adalah sekitar indeks yang difilter. Saya mengerti bahwa saya dapat menempatkan filter pada indeks seperti "WHERE IsDeleted = 0" untuk mengurangi ukuran indeks. Namun, karena setiap join / kueri harus mengimplementasikan cek IsDeleted, apakah itu akan mencegah indeks difilter dari digunakan (karena kolom IsDeleted digunakan dalam join / query)?

Ingat, saya tidak memiliki kemampuan untuk mengubah pendekatan IsDeleted.

Philᵀᴹ
sumber

Jawaban:

13

Pendekatan termudah di sini adalah membiarkan kunci dan indeks cluster Anda sendiri, dan menggunakan indeks yang difilter untuk indeks non-cluster Anda.

Selain itu, Anda dapat memigrasi beberapa tabel besar ke tumpukan yang dipartisi atau toko clustered-clustered (SQL Server 2016+), membiarkan kunci utama dan indeks unik tidak dipartisi. Ini akan memungkinkan Anda untuk mendorong kolom non-kunci untuk baris IsDeleted ke struktur data terpisah, yang juga dapat dikompres secara berbeda atau disimpan pada grup file yang berbeda.

Dan pastikan pengembang menggunakan literal alih-alih parameter untuk memfilter baris IsDeleted. Dengan parameter SQL Server harus menggunakan rencana permintaan yang sama untuk kedua kasus.

MISALNYA

SELECT ... WHERE ... AND IsDeleted=0

Dan tidak:

SELECT ... WHERE ... AND IsDeleted=@IsDeleted

Menggunakan paramter akan mencegah penggunaan indeks yang difilter, dan dapat membuat Anda mendapat masalah dengan sniffing parameter.

David Browne - Microsoft
sumber
Mengingat keberadaan dan pentingnya IsDeletedkolom, terlepas dari penyimpanan fisik, mungkin masuk akal untuk mengekspos data melalui dua tampilan (opsional dalam skema yang berbeda), menyelesaikan masalah parameterisasi dan membuat kesalahan dengan mengakses data yang seharusnya tidak diakses lebih kecil kemungkinannya. Mengakses data dasar hanya relevan untuk kasus-kasus langka di mana data yang dihapus dan tidak terhapus perlu digabungkan entah bagaimana, dan ketika baris sebenarnya perlu diubah ke "dihapus".
Jeroen Mostert
@ JoenenMostert saran yang bagus. RLS juga dapat digunakan di sini, atau sesuatu seperti EF Core Global Query Filters. docs.microsoft.com/en-us/ef/core/querying/filters
David Browne - Microsoft
9

Ini mungkin pendapat yang tidak populer, tapi saya rasa tidak ada "lakukan ini di mana-mana" / satu ukuran cocok untuk semua jawaban atas pertanyaan Anda.

Jika Anda memiliki kueri yang memindai banyak baris IsDeleted tanpa alasan, salah satu solusinya adalah membuat indeks yang difilter dan tidak disaring untuk memenuhi kueri itu.

Opsi lain adalah membuat tampilan yang diindeks yang dapat dimanfaatkan oleh sejumlah kueri yang berbeda, yang difilter hanya ke baris yang tidak dihapus. Ini bisa sangat berguna pada Edisi Perusahaan, di mana pencocokan tampilan terindeks otomatis berfungsi tanpa memberikan NOEXPANDpetunjuk.

Untuk tabel kecil, atau tabel yang banyak dibaca, menambahkan indeks atau tampilan nonclustered yang difilter atau yang lainnya mungkin hanya menambahkan overhead yang tidak perlu ke dalam database Anda.

Josh Darnell
sumber
2

Di bawah asumsi masuk akal bahwa penghapusan jarang terjadi, tidak ada perubahan pada indeks adalah solusi yang tepat.

Saya menemukan bahwa cepat atau lambat orang harus meminta referensi untuk baris yang dihapus, dan baris yang ada dalam indeks tiba-tiba sangat berharga.

Harap perhatikan bahwa kecuali jika Anda menggunakan tampilan, Anda harus mengedit semua pertanyaan Anda untuk tetap menyertakan filter.

Joshua
sumber
0

Saya telah melihat sistem di mana bendera IS_DELETED bernilai 0 atau nilai PK. Dalam sistem lain itu adalah negatif dari PK.

Karena sebagian besar kueri mengambil nilai dengan kunci "alami" atau bisnis (terkadang multi-bidang), mereka tidak pernah ditanyai oleh PK kecuali melalui gabungan; tetapi mereka selalu menambahkan AND IS_DELETED = 0 di akhir untuk tabel utama dan untuk semua tabel yang tergabung.

Sistem ini juga memiliki tabel audit untuk setiap tabel transaksional yang melacak perubahan; dan aplikasi memiliki fitur untuk menampilkan semua perubahan data termasuk data yang dihapus.

Rick Ryker
sumber
0

Semoga Anda memiliki hak dan kemampuan untuk mengubah kueri.

Namun, karena setiap join / kueri harus mengimplementasikan cek IsDeleted, apakah itu akan mencegah indeks difilter dari digunakan (karena kolom IsDeleted digunakan dalam join / query)?

Saya ingin mengatakan satu poin penting, semoga saya bisa menjelaskannya.

Dalam kueri kompleks di mana Transaction tabledan Mastertabel keduanya digunakan.

Gunakan IsDeleted=0hanya dalam Transactiontabel. Jangan gunakan dalam Mastertabel.

Contoh,

Select * from dbo.Order O
inner join dbo.category C on o.categoryid=o.categoryid
inner join dbo.Product P on P.Productid=o.Productid
where o.isdeleted=0

Tidak ada gunanya c.isdeleted=0(menggunakan dalam Categorytabel). Tidak perlu.

Demikian pula apakah ada gunanya menggunakan P.isdeleted=0?

Karena saya ingin semua Urutan yang belum dihapus dan detailnya.

Bagaimana bisa Productdihapus saat Orderini Activeatau di mana pun Productidadalah referensi.

Jadi dengan cara ini jika Anda men-debug dengan hati-hati dalam permintaan penting, maka mungkin Anda dapat menghapus beberapa isdeleted = 0.

Jangan membabi buta Buat Indeks yang Difilter, pertama-tama pilih semua permintaan yang sangat penting dan lambat itu.

Optimalkan kueri lambat itu lalu tentukan saja tentang Indeks Tersaring atau Indeks Selaras.

KumarHarsh
sumber