Desain database SQL Server untuk data "diarsipkan tetapi tersedia"

12

Kami memiliki basis data besar ini (> 1TB) yang kami maksudkan untuk "menyusut". Basis data berputar di sekitar satu entitas utama, sebut saja "Kunjungi". Untuk diskusi, katakanlah ini adalah basis data untuk praktik medis.

Ada total 30 "jenis" kunjungan, seperti prosedur, tahunan, tindak lanjut, imunisasi dll, yang masing-masing merupakan tabel tambahan untuk "Kunjungi", misalnya "visit_immuno".

Basis data telah mengakumulasikan sekitar 12 tahun data sejak tahun 2000. Seseorang telah mengusulkan agar kami menyimpan sekitar 3 tahun data dalam versi "live" dan sisanya tinggal dalam database "old_data". Tanggal HANYA disimpan dalam tabel "Kunjungan" karena dinormalisasi. Tabel Kunjungan juga berisi ROWVERSIONkolom dan kolom BIGINTidentitas palsu (berkerumun). Untuk semua maksud dan tujuan, katakanlah kunci pengelompokan diisi oleh SEQUENCE (SQL Server 2012 Enterprise) - kami akan menamainya cid.

Tidak visit.dateselalu dalam urutan yang sama dengan kunci pengelompokan, misalnya ketika seorang dokter melakukan kunjungan yang diperpanjang dan kembali dengan "koper" datanya, itu akan digabungkan ke dalam tabel utama. Ada juga beberapa pembaruan pada tabel "kunjungan" yang akan menyebabkan ROWVERSIONkolom tidak sinkron dengan kolom ciddan date- untuk membuatnya lebih sederhana, tidak ROWVERSIONjuga tidak cidakan membuat kunci partisi yang sesuai untuk alasan ini.

Aturan bisnis untuk menghapus data dari "langsung" adalah bahwa visit.dateharus lebih dari 36 bulan danvisit_payment catatan anak harus ada. Juga, database "old_data" tidak mengandung tabel dasar kecuali visit%.

Jadi kita berakhir dengan:

Live DB (penggunaan sehari-hari) - Semua tabel Data Lama DB - data lama untuk visit%tabel

Proposal membutuhkan DB Gabungan yang merupakan shell yang berisi Sinonim untuk SEMUA tabel dasar dalam Live DB(kecuali visit%) plus Tampilan yang UNION ALL di seluruh visit%tabel dalam dua database.

Dengan asumsi indeks yang sama dibuat di Old-DataDB, apakah kueri berkinerja baik di UNION-ALL Views ? Jenis pola kueri apa yang mungkin meningkatkan rencana pelaksanaan untuk Tampilan UNION-ALL ?

孔夫子
sumber
3
Apa motivasi untuk a) pengarsipan data lama dan b) menjaganya agar tetap dapat diakses? Pemeliharaan overhead? Masalah kinerja? Apakah data yang diarsipkan harus dapat diakses secara mulus ke aplikasi? Dengan atau tanpa modifikasi aplikasi?
Mark Storey-Smith
(a) Menjaga db utama tetap kecil. Ini direplikasi ke 3 envs lainnya - dev, pre-test, test. Ada juga cermin dan cadangan yang direplikasi, semua didukung oleh penyimpanan yang mahal. (B) Karena sistem hilir saat ini memiliki akses ke semua data, jadi ini mempertahankan status quo. (c) Sebuah instance dari aplikasi dapat berjalan terhadap DB "gabungan" dengan semua tampilan, tapi saya curiga mungkin tidak bekerja sama sekali.
孔夫子
Sekadar klarifikasi, data yang diarsipkan masih baca-tulis, benar? Atau hanya baca?
Jon Seigel
Data lama akan berubah menjadi hanya-baca dan halaman yang diisi 100%. Mesin virtual dari aplikasi yang terhubung ke tampilan gabungan dapat membuat kesalahan jika seseorang mencoba sesuatu yang konyol pada data lama - kami tidak peduli.
孔夫子
Saya pikir filegroup read-only untuk data historis dan backup / restore parsial akan membahas hal ini, tanpa tambahan kotoran dari basis data shell dan sinonim. Saya katakan berpikir karena saya belum ikut campur dengan mekanisme itu untuk beberapa waktu dan perlu menyegarkan ingatan saya. Tidak tahu bagaimana itu akan sesuai dengan replikasi, tetapi saya akan mempertanyakan mengapa Anda mereplikasi database langsung ke lingkungan hilir.
Mark Storey-Smith

Jawaban:

4

Untuk kenyamanan, anggaplah bahwa live database dipanggil LiveDbdan database yang berhasil disebutArchiveDb

  • Tambahkan tampilan UNION ALL dalam LiveDbmenunjuk ke tabel dalam ArchiveDbdatabase melalui sinonim (Tidak perlu melakukan db gabungan dengan sinonim)
  • "Partisi" aktif visit.datedan nonaktifkan juga kolom ini visit_paymentsjika belum ada (ini meningkatkan kinerja gabungan yang ditempatkan bersama)
  • Arsipkan hanya dua tabel besar jika memungkinkan (mengurangi kemungkinan tersandung pengoptimal). Pertahankan tampilan UNION ALL dan tabel lainnya LiveDbagar semua yang tergabung ke tabel yang lebih kecil disimpan secara lokal
  • Tambahkan batasan PERIKSA pada tabel di keduanya LiveDbdan ArchiveDb yang menjelaskan kisaran yang visit.dateterkandung dalam tabel. Ini membantu optimiser menghilangkan tabel arsip dari pencarian dan pemindaian yang berisi kolom visit.data. Anda harus memperbarui batasan ini secara berkala.
  • Pada tampilan UNION ALL, tambahkan kriteria WHERE yang difilter visit.data. Ini merupakan tambahan untuk petunjuk yang telah Anda berikan dalam batasan pemeriksaan. Ini memaksimalkan kemungkinan filter ditekan ke bawah
  • Jika Anda memiliki EE, partisi tabel dalam database arsip (Tapi BUKAN dalam database hidup). Jika Anda ingin menjadi benar-benar mewah, gunakan cadangan / pemulihan tingkat arsip dari basis data grup untuk menghemat waktu cadangan.
  • Pertimbangkan untuk memasukkan AchiveDbmode pemulihan SEDERHANA jika belum. Anda tidak akan memerlukan cadangan log transaksiArchiveDb
  • Gunakan INSERT ... WITH (TABLOCK) SELECT ... WITH (ROWLOCK) untuk memaksa penebangan minimal pada tujuan saat memindahkan data antara LiveDbdanArchiveDb

Semua hal di atas tidak menjamin bahwa pengoptimal akan menghilangkan tabel arsip dari pencarian dan pemindaian, tetapi itu membuatnya lebih mungkin.

Ketika eliminasi tidak terjadi. Ini adalah efek yang mungkin Anda lihat (daftar ini mungkin tidak lengkap). Untuk mencari, Anda akan mendapatkan pencarian tambahan pada setiap permintaan (ini menaikkan IOPS). Untuk pemindaian, hasilnya bisa menjadi bencana bagi kinerja karena Anda dapat memindai tabel arsip dan tabel langsung. Berikut adalah cara-cara khas yang dapat Anda gunakan untuk meningkatkan optimizer:

  • Jika Anda bergabung dengan visit%tabel bersama dan tidak termasuk visit.datadalam kriteria bergabung (inilah sebabnya Anda ingin menormalkan kembali). Karena itu, Anda mungkin ingin memodifikasi beberapa pertanyaan Anda
  • Jika Anda mendapatkan hash join antara visit.datadan tabel lain (misalnya dimensi tanggal), Anda mungkin tidak mendapatkan penghapusan tabel yang benar
  • Jika Anda mencoba untuk mengumpulkan data di atas tabel yang diarsipkan
  • Jika Anda memfilter pada sesuatu TETAPI visit.data, misalnya pencarian langsung pada kunci tampilan.

Untuk skenario terakhir, Anda dapat melindungi diri Anda dari efek terburuk dengan menambahkan batasan pemeriksaan lain pada cid- jika ini memungkinkan. Anda memang menyebutkan bahwa urutan cidtidak "bersih" sehubungan dengan tanggal dan perkembangan baris dalam tabel. Namun, dapatkah Anda mempertahankan tabel yang berisi informasi: "Tidak ada cidnomor di atas ini sejak ini visit.data" atau serupa? Ini kemudian dapat mendorong kendala tambahan.

Hal lain yang perlu diperhatikan adalah bahwa kueri paralel dapat menghasilkan BANYAK utas lebih banyak setelah Anda meminta tampilan yang dipartisi (karena kedua "sub-tabel" akan terkena optimisasi paralel yang sama). Untuk alasan itu, Anda mungkin ingin membatasi MAXDOP di server atau kueri yang paralel.

Omong-omong, jika Anda tahu kueri dengan baik - Anda bahkan mungkin tidak perlu indeks yang sama di dua database (ini mengasumsikan Anda 100% yakin Anda akan mendapatkan penghapusan tabel yang tepat). Anda bahkan dapat mempertimbangkan menggunakan toko kolom untuk ArchiveDb.

Thomas Kejser
sumber
-1

Cara yang kami lakukan adalah menulis data lama dalam batch ke database yang baru dibuat dan menghapus data lama dari live db. Dengan begitu kedua db dapat diakses. Anda juga dapat membuat cadangan database yang baru dibuat dan mengembalikannya di tempat lain untuk menghapus jejak besar dari server produksi. Semoga itu adalah solusi yang dapat diterima untuk kebutuhan Anda.

Subhash Pant
sumber
OP perlu melangkah lebih jauh dari ini untuk menjaga kompatibilitas aplikasi. Apakah Anda membaca pertanyaannya?
Jon Seigel