Tandai vs perpecahan tabel

10

Saya mendesain daftar item yang akan (berpotensi) berisi puluhan juta rekaman. Beberapa item tidak akan tersedia untuk digunakan sampai mereka "disetujui" oleh administrator. Dengan "menggunakan" maksud saya bahwa barang-barang tersebut tidak akan dirujuk dalam tabel lain sampai mereka "disetujui". Hingga 50% item mungkin "tidak disetujui" pada waktu tertentu. Catatan mungkin menjadi "disetujui", tetapi tidak sebaliknya.

Saya mempertimbangkan dua opsi desain:

  • bendera sedikit
  • tabel terpisah dari item "tidak disetujui" - ketika item disetujui itu dipindahkan ke tabel "biasa" (pembaruan ID item tidak menjadi masalah)

Saya pikir opsi kedua jauh lebih baik. Bendera bit hanya membutuhkan satu byte per baris, jadi ini bukan masalah. Tetapi jika kita memiliki sejuta catatan yang disetujui dan satu juta catatan yang tidak disetujui dalam tabel yang sama - waktu pindai meningkat untuk operasi dengan catatan yang disetujui.

Pertanyaannya adalah: apakah saya harus mempertimbangkan opsi pertama (bit flag)? Apakah ada manfaatnya dalam situasi yang digambarkan?

Dima
sumber
1
Mungkin membantu untuk mengingat bahwa Anda dapat menggunakan indeks yang difilter untuk membantu mempercepat akses ke catatan yang disetujui. brentozar.com/archive/2013/11/…
mendosi
Sayangnya indeks yang difilter tidak digunakan dalam permintaan parameter.
Dima
@ Dima, itu tidak sepenuhnya benar. Jika indeks yang difilter mengatakan WHERE status='A'dan memiliki permintaan WHERE status = 'A' AND (... other columns and parameters here...), maka indeks tersebut mungkin masih digunakan.
ypercubeᵀᴹ

Jawaban:

6

Anda dapat memiliki keduanya dengan tampilan yang dipartisi .

Anda membuat tabel yang mendasari untuk setiap status, ditegakkan oleh kendala, dengan nilai-nilai yang saling eksklusif. Kemudian pandangan yang UNION bersama-sama tabel yang mendasarinya. Tampilan atau setiap tabel dasar dapat dirujuk secara eksplisit. Jika status baris adalah UPDATEd melalui tampilan, DBMS akan HAPUS dari satu tabel dasar dan masukkan ke yang sesuai dengan status baru. Setiap tabel dasar dapat diindeks secara independen sesuai dengan pola penggunaannya. Pengoptimal akan menyelesaikan referensi indeks ke satu tabel basis yang sesuai jika bisa.

Manfaatnya adalah
a) indeks dangkal. Akan tetapi, lakukan penghitungan indeks dengan menggunakan fan-out. Pada skala itu dan pisahkan antara nilai status Anda, mungkin indeksnya akan memiliki kedalaman yang sama pada tabel pisah seperti pada tabel gabungan.
b) tidak ada kode aplikasi yang harus diubah. Data terus muncul sebagai keseluruhan yang berkelanjutan.
c) nilai status baru di masa mendatang dapat dimasukkan dengan menambahkan tabel dasar baru, dengan kendala, dan menciptakan kembali tampilan.

Biaya adalah semua pergerakan data itu; dua halaman dan indeks terkait ditulis untuk setiap pembaruan status. Banyak IO yang harus dihadapi. Gerakan sebanyak itu akan menyebabkan fragmentasi juga.

Michael Green
sumber
5

tabel item yang akan (berpotensi) berisi puluhan juta catatan.

Itu sebenarnya tidak banyak, mengingat apa yang SQL Server dapat efisien menangani. Tentu saja, saya ingat salah satu pekerjaan saya sebelumnya di mana salah satu meja terbesar (sistem instance-tunggal) memiliki 2 juta baris dan itu adalah yang paling saya pernah ditangani. Kemudian pekerjaan berikutnya memiliki 17 instance Produksi dengan beberapa tabel memiliki ratusan juta baris, dan semuanya dikumpulkan ke dalam Gudang Data dengan beberapa tabel fakta yang memiliki lebih dari 1 miliar baris. Jangan salah paham, saya tidak mengejek puluhan juta baris, saya hanya menekankan bahwa dengan model data yang baik dan pengindeksan yang tepat (dan pemeliharaan indeks), SQL Server dapat menangani banyak hal .

Hingga 50% item mungkin "tidak disetujui" pada waktu tertentu.

Hmm. Kedengarannya tidak benar. Tingkat entri "menyetujui" akan menjadi setengah tingkat mendapatkan entri baru? Untuk setiap 2 entri baru, hanya 1 yang akan "disetujui"? Dalam contoh Anda 2 juta baris, dan 1 juta masing-masing untuk "disetujui" dan "tidak disetujui", beberapa tahun kemudian dengan 10 juta entri lainnya, Anda mengharapkan masing-masing 6 juta untuk "disetujui" dan "tidak disetujui"? Atau apakah 1 juta "tidak disetujui" akan tetap agak konstan, sehingga dengan 10 juta entri baru, akan ada 11 juta "disetujui" dan masih 1 juta "tidak disetujui"?

Catatan mungkin menjadi "disetujui", tetapi tidak sebaliknya.

Itu benar hari ini , tetapi banyak hal berubah dari waktu ke waktu sehingga selalu ada kemungkinan bahwa bisnis dapat memutuskan untuk mengizinkan "tidak disetujui", atau mungkin beberapa status lain, seperti "diarsipkan", dll.

Jadi, mari kita lihat pilihannya:

Tandai (atau bahkan TINYINT"status")

  • Sedikit lebih lambat untuk kueri dari setiap status
  • Lebih fleksibel dari waktu ke waktu / mudah untuk memasukkan perubahan seperti status ketiga (mis. "Diarsipkan") dengan hanya nilai status Pencarian baru. Tidak ada tabel baru (tentu saja), beberapa kode baru, hanya beberapa kode yang diperbarui.
  • Lebih sedikit pekerjaan (mis. Kode, pengujian, dll) dan sedikit ruang untuk kesalahan memperbarui satu TINYINTkolom
  • Kurang rumit = biaya perawatan yang lebih rendah seiring waktu, waktu pelatihan yang lebih singkat bagi karyawan baru untuk mencari tahu
  • (mungkin) Dampak yang lebih kecil terhadap Log Transaksi saat satu tabel diperbarui
  • Hanya perlu tabel pencarian untuk "RecordStatus" dan FK antara dua tabel.

Dua tabel terpisah (satu untuk "disetujui", satu untuk "tidak disetujui")

  • Sedikit lebih cepat untuk kueri dari setiap status
  • Kurang fleksibel dari waktu ke waktu / lebih sulit untuk memasukkan perubahan seperti keadaan ketiga (mis. "Diarsipkan"); negara baru akan membutuhkan kemungkinan besar tabel lain, dan kode pasti baru dan diperbarui.
  • Lebih banyak pekerjaan (yaitu kode, pengujian, dll) dan lebih banyak ruang untuk catatan pemindahan kesalahan dari tabel "Tidak disetujui" ke tabel "Disetujui"
  • Lebih rumit = biaya perawatan yang lebih tinggi dari waktu ke waktu, lebih lama waktu pelatihan bagi karyawan baru untuk mencari tahu
  • (mungkin) Dampak lebih besar terhadap Log Transaksi ketika satu tabel dihapus dan satu dimasukkan
  • Tidak perlu khawatir tentang " pembaharuan ID item ": tabel tidak disetujui memiliki ID kolom yang merupakan IDENTITYkolom, dan meja Disetujui memiliki ID kolom yang tidak merupakan IDENTITY(karena tidak dibutuhkan di sana). Karenanya nilai ID tetap konsisten saat rekaman bergerak di antara tabel.

Secara pribadi, saya akan bersandar ke meja tunggal dengan StatusIDkolom untuk memulai. Menggunakan dua tabel tampaknya seperti optimasi prematur yang terlalu rumit. Jenis optimasi itu dapat didiskusikan jika / ketika jumlah catatan dalam beberapa ratus juta dan pengindeksan tidak memberikan keuntungan kinerja apa pun.

Solomon Rutzky
sumber
Ini adalah tabel dengan data yang bergerak cepat: cukup sering diisi dengan banyak baris baru, cukup sering baris dihapus. Saya mencoba menghapus semua detail (seperti keputusan bisnis, pengkodean klien, dll.) Untuk berkonsentrasi hanya pada satu topik. Pada dasarnya kami memiliki tabel desain lama dengan sedikit bendera. Dan saya tahu untuk 100% bahwa baris di mana bendera diatur ke 1 tidak pernah digunakan di tabel lain. Jadi saya merasa bahwa mereka hanya terjadi di sana dan dapat dipindahkan ke meja terpisah. Tabel dipindai hampir di setiap permintaan ke DB. Jadi mengurangi "berat" -nya secara potensial dapat mengurangi operasi CPU / IO.
Dima
3
Keuntungan lain dari tabel split: Anda dapat memiliki FK yang hanya merujuk tabel "Disetujui".
ypercubeᵀᴹ
Masalah lain dengan tabel split untuk satu entitas adalah integritas kendala. Referensi dari tabel lain tidak akan bermain bagus dengan catatan bergerak. Ini akan membutuhkan kode untuk ditulis untuk mengatasi masalah ini seperti tabel referensi mirror untuk tabel split -> Sangat merepotkan
user1567453