Mendukung Kekekalan dalam Desain Basis Data

26

Salah satu item dalam Java Efektif Joshua Bloch adalah gagasan bahwa kelas harus memungkinkan mutasi instance sesedikit mungkin, dan lebih disukai tidak sama sekali.

Seringkali, data suatu objek disimpan ke database dari beberapa bentuk. Hal ini membuat saya berpikir tentang ide kekekalan dalam database, terutama untuk tabel-tabel yang mewakili satu kesatuan dalam sistem yang lebih besar.

Sesuatu yang saya telah bereksperimen dengan baru-baru ini adalah gagasan untuk mencoba meminimalkan pembaruan yang saya lakukan pada baris tabel yang mewakili objek-objek ini, dan mencoba melakukan sisipan sebanyak yang saya bisa.

Contoh nyata dari sesuatu yang saya coba-coba baru-baru ini. Jika saya tahu saya mungkin menambahkan catatan dengan data tambahan nanti, saya akan membuat tabel lain untuk mewakili itu, seperti dua definisi tabel berikut:

create table myObj (id integer, ...other_data... not null);
create table myObjSuppliment (id integer, myObjId integer, ...more_data... not null);

Mudah-mudahan jelas bahwa nama-nama ini bukan kata demi kata, tetapi hanya untuk menunjukkan idenya.

Apakah ini pendekatan yang masuk akal untuk pemodelan ketekunan data? Apakah layak mencoba membatasi pembaruan yang dilakukan di atas meja, terutama untuk mengisi nol untuk data yang mungkin tidak ada saat catatan awalnya dibuat? Apakah ada saat-saat ketika pendekatan seperti ini dapat menyebabkan rasa sakit yang parah di kemudian hari?

Ed Carrel
sumber
7
Saya merasa ini adalah solusi tanpa masalah ... Anda harus memperbarui, daripada membuat adaptasi yang rumit untuk menghindari pembaruan.
Fosco
Saya pikir itu lebih merupakan masalah memiliki ide intuitif dari solusi dalam pikiran, dan ingin menjalankannya oleh sebanyak mungkin orang, dan dalam proses menyadari bahwa ini mungkin bukan solusi terbaik untuk masalah yang saya miliki. Saya dapat membuka pertanyaan berbeda dengan masalahnya, asalkan saya tidak dapat menemukannya di tempat lain.
Ed Carrel
1
Mungkin ada alasan bagus untuk menghindari pembaruan di basis data. Namun, ketika alasan ini muncul, ini lebih merupakan masalah pengoptimalan dan karena itu tidak boleh dilakukan tanpa bukti bahwa ada masalah.
dietbuddha
6
Saya pikir ada argumen kuat untuk kekekalan dalam database. Ini memecahkan banyak masalah. Saya pikir komentar negatif belum datang dari orang-orang yang berpikiran terbuka. Pembaruan di tempat adalah penyebab dari begitu banyak masalah. Saya berpendapat bahwa kita memiliki semuanya mundur. Pembaruan di tempat adalah solusi lawas untuk masalah yang tidak ada lagi. Penyimpanan murah. Kenapa melakukannya? Berapa banyak sistem DB memiliki log audit, sistem versi, kebutuhan untuk replikasi terdistribusi yang seperti yang kita semua tahu membutuhkan kemampuan untuk mendukung latensi untuk skala. Kekekalan menyelesaikan semua ini.
Cirrus
@Fosco Beberapa sistem mutlak diperlukan untuk tidak pernah menghapus data (termasuk menggunakan UPDATE). Seperti catatan medis dokter.
Izkata

Jawaban:

25

Tujuan utama dari immutability adalah untuk memastikan bahwa tidak ada waktu instan ketika data dalam memori dalam keadaan tidak valid. (Yang lain adalah karena notasi matematika sebagian besar statis, dan hal-hal yang tidak berubah lebih mudah untuk dikonseptualisasikan dan dimodelkan secara matematis.) Dalam memori, jika utas lain mencoba membaca atau menulis data saat sedang dikerjakan, mungkin akhirnya akan rusak, atau itu sendiri mungkin dalam keadaan korup. Jika Anda memiliki beberapa operasi penugasan ke bidang objek, dalam aplikasi multithreaded, utas lain mungkin mencoba bekerja dengannya di antaranya - yang mungkin buruk.

Immutability memperbaiki hal ini dengan pertama-tama menulis semua perubahan ke tempat baru di memori, dan kemudian melakukan tugas akhir sebagai satu langkah silih berganti penulisan pointer ke objek untuk menunjuk ke objek baru - yang pada semua CPU merupakan atom. operasi.

Basis data melakukan hal yang sama menggunakan transaksi atom : ketika Anda memulai transaksi, ia menulis semua pembaruan baru ke tempat baru pada disk. Ketika Anda menyelesaikan transaksi, itu mengubah pointer pada disk ke tempat pembaruan baru - yang dilakukannya dalam waktu singkat di mana proses lain tidak bisa menyentuhnya.

Ini juga hal yang persis sama dengan ide Anda membuat tabel baru, kecuali lebih otomatis dan lebih fleksibel.

Jadi untuk menjawab pertanyaan Anda, ya, kekekalan bagus dalam database, tetapi tidak, Anda tidak perlu membuat tabel terpisah hanya untuk tujuan itu; Anda bisa menggunakan perintah transaksi atom apa pun yang tersedia untuk sistem basis data Anda.

Rei Miyasaka
sumber
Terima kasih atas jawabannya. Perspektif ini adalah apa yang saya butuhkan untuk menyadari bahwa intuisi saya membingungkan mencoba untuk menggabungkan beberapa ide yang berbeda menjadi satu pola tunggal.
Ed Carrel
8
Ada sedikit lebih dari itu daripada atmosfer. Argumen yang paling sering saya lihat dalam mendukung ketidakmampuan dalam konteks OOP adalah bahwa objek yang tidak dapat diubah hanya mengharuskan Anda untuk memvalidasi keadaan mereka satu kali, dalam konstruktor. Jika mereka bisa berubah, maka setiap metode yang dapat mengubah keadaan mereka diharuskan juga memverifikasi bahwa keadaan yang dihasilkan masih valid, yang dapat menambah kompleksitas yang signifikan ke kelas. Argumen ini berpotensi berlaku untuk basis data juga, tetapi jauh lebih lemah, karena aturan validasi db cenderung bersifat deklaratif daripada prosedural, sehingga tidak perlu diduplikasi untuk setiap kueri.
Dave Sherohman
24

Itu tergantung pada manfaat apa yang Anda harapkan dari ketidakberdayaan. Jawaban Rei Miyasaka ditujukan pada satu (penghindaran kondisi perantara yang tidak valid), tetapi inilah yang lain.

Mutasi kadang-kadang disebut pembaruan destruktif : ketika Anda bermutasi suatu objek, keadaan lama hilang (kecuali Anda mengambil langkah-langkah tambahan untuk secara eksplisit melestarikannya entah bagaimana). Sebaliknya, dengan data yang tidak dapat diubah, sepele untuk secara simultan mewakili negara baik sebelum dan sesudah beberapa operasi, atau untuk mewakili beberapa negara penerus. Bayangkan mencoba menerapkan pencarian pertama dengan memutasikan satu objek negara.

Ini mungkin muncul di dunia database paling sering sebagai data temporal . Katakan bulan lalu Anda menggunakan paket Basic, tetapi pada tanggal 16 Anda beralih ke paket Premium. Jika kami hanya menimpa beberapa bidang yang menunjukkan rencana apa yang Anda jalankan, kami mungkin mengalami kesulitan dalam penagihan. Kami mungkin juga kehilangan kemampuan untuk menganalisis tren. (Hei, lihat apa yang dilakukan kampanye iklan lokal ini!)

Itulah yang terlintas di pikiran saya ketika Anda mengatakan "kekekalan dalam desain basis data".

Ryan Culpepper
sumber
2
Saya tidak setuju dengan paragraf ketiga Anda. Jika Anda ingin memiliki riwayat (log audit, log perubahan rencana, dll.), Anda harus membuat tabel terpisah untuk ini. Menggandakan semua 50 bidang Customertabel hanya untuk mengingat bahwa pengguna mengubah rencana tidak membawa apa-apa selain kelemahan kinerja yang besar, pemilihan yang lebih lambat dari waktu ke waktu, penambangan data yang lebih rumit (dibandingkan dengan log) dan lebih banyak ruang yang terbuang.
Arseni Mourzenko
6
@ MainMa: mungkin saya seharusnya mengatakan "baca tentang database temporal" sebagai gantinya. Contoh saya dimaksudkan sebagai sketsa data temporal apa itu; Saya tidak mengklaim itu selalu cara terbaik untuk mewakili perubahan data. Di sisi lain, sementara dukungan untuk data temporal saat ini cukup buruk, saya berharap kecenderungan untuk mengakomodasi data temporal dalam database itu sendiri, daripada menyerahkannya ke representasi "kelas dua" seperti log perubahan.
Ryan Culpepper
Bagaimana jika kita mempertahankan riwayat perubahan dalam tabel audit (boot spring dan hibernasi misalnya dari kemampuan ini)?
Mohammad Najar
14

Jika Anda tertarik pada manfaat yang bisa Anda dapatkan dari ketidakmampuan dalam suatu basis data, atau setidaknya suatu basis data yang menawarkan ilusi ketidakmampuan, periksa Datomic.

Datomic adalah Basis Data yang ditemukan oleh Rich Hickey dalam aliansi dengan Think Relevance, ada banyak video yang menjelaskan arsitektur, tujuan, dan model data. Cari infoq, satu khususnya berjudul Datomic, Database as a Value . Dalam kebingungan Anda dapat menemukan keynote yang diberikan oleh Rich Hickey di konferensi euroclojure pada tahun 2012. confreaks.com/videos/2077-euroclojure2012-day-2-keynote-the-datomic-architecture-and-data-model

Ada pembicaraan di vimeo.com/53162418 yang lebih berorientasi pengembangan.

Ini ada satu lagi dari stuart halloway di.pscdn.net/008/00102/videoplatform/kv/121105techconf_close.html

  • Datomic adalah basis data fakta dalam waktu, yang disebut datums, dalam 5-tupel [E, A, V, T, O]
    • E Entity id
    • Sebuah nama Atribut dalam entitas (dapat memiliki ruang nama)
    • Nilai V atribut
    • T ID Transaksi, dengan ini Anda memiliki gagasan tentang waktu.
    • O Satu operasi penegasan (nilai sekarang atau saat ini), penolakan (nilai masa lalu);
  • Menggunakan format data sendiri, yang disebut EDN (Extensible Data Notation)
  • Transaksi adalah ASAM
  • Menggunakan datalog sebagai bahasa kueri, yang bersifat deklaratif sebagai kueri SQL + rekursif. Kueri diwakili dengan struktur data, dan diperluas dengan bahasa jvm Anda, Anda tidak perlu menggunakan clojure.
  • Basis data dipisahkan dalam 3 layanan terpisah (proses, mesin):
    • Transaksi
    • Penyimpanan
    • Mesin Pertanyaan.
  • Anda dapat secara terpisah, skala setiap layanan.
  • Ini bukan open source, tetapi ada versi gratis (seperti dalam bir) dari Datomic.
  • Anda dapat menyatakan skema yang fleksibel.
    • set atribut terbuka
    • tambahkan atribut baru kapan saja
    • tidak ada kekakuan dalam definisi atau kueri

Sekarang, karena info disimpan sebagai fakta dalam waktu:

  • semua yang Anda lakukan adalah menambahkan fakta ke basis data, Anda tidak pernah menghapusnya (kecuali jika diharuskan oleh hukum)
  • Anda bisa menyimpan semuanya selamanya. Query Engine, tinggal di server aplikasi sebagai basis data dalam memori (untuk bahasa jvm, bahasa non-jvm memiliki akses melalui REST API.)
  • Anda dapat meminta pada waktu di masa lalu.

Basis data adalah nilai, dan parameter ke mesin kueri, QE mengelola koneksi dan caching. Karena Anda dapat melihat db sebagai nilai, dan struktur data yang tidak dapat diubah dalam memori, Anda dapat menggabungkannya dengan struktur data lain yang dibuat dari nilai "di masa depan" dan meneruskannya ke QE & kueri dengan nilai masa depan, tanpa mengubah database aktual .

Ada proyek open source dari Rich Hickey, yang disebut codeq , Anda dapat menemukannya di github Datomic / codeq, yang memperluas model git, dan menyimpan referensi ke objek git dalam database bebas datomik, dan membuat kueri kode Anda, Anda dapat melihat contoh cara menggunakan datomic.

Anda dapat menganggap datomik sebagai ACID NoSQL, dengan datum Anda dapat memodelkan tabel atau dokumen atau Kv-store atau grafik.

kisai
sumber
7

Gagasan untuk menghindari pembaruan, dan lebih suka menyisipkan, adalah salah satu pemikiran di balik membangun penyimpanan data Anda sebagai Sumber Kejadian, sebuah ide yang sering Anda temukan digunakan bersama dengan CQRS. Dalam model sumber acara, tidak ada pembaruan: agregat diwakili sebagai urutan "transformasi" (peristiwa), dan akibatnya penyimpanan hanya ditambahkan.
Situs ini berisi diskusi menarik tentang CQRS dan sumber acara, jika Anda ingin tahu tentang itu!

Mathias
sumber
Sumber CQRS dan Acara menjadi sorotan akhir-akhir ini.
Gulshan
6

Ini memiliki hubungan yang sangat dekat dengan apa yang dikenal sebagai "Dimensi Perlahan Berubah" di dunia pergudangan data, dan tabel "Temporal" atau "Bi-Temporal" di domain lain.

Konstruk dasarnya adalah:

  1. Selalu gunakan kunci pengganti yang dihasilkan sebagai kunci utama.
  2. Pengidentifikasi unik dari apa pun yang Anda gambarkan menjadi "kunci logis".
  3. Setiap baris harus memiliki setidaknya stempel waktu "ValidFrom" dan secara opsional stempel waktu "ValidTo" dan bahkan lebih opsional bendera "Versi Terbaru".
  4. Pada "penciptaan" entitas logis Anda Sisipkan baris baru dengan "Berlaku Dari" cap waktu saat ini. ValidTo opsional diatur ke "selamanya" (9999-12-31 23:59:59) dan Versi Terakhir menjadi "Benar".
  5. Pada pembaruan selanjutnya dari entitas logis. Anda setidaknya memasukkan baris baru seperti di atas. Anda juga mungkin perlu menyesuaikan ValidTo pada versi sebelumnya menjadi "now () - 1 detik" dan Versi Terbaru ke "False"
    1. Pada penghapusan logis (ini hanya bekerja dengan timestamp ValidTo!) Anda mengatur bendera ValidTo di baris saat ini ke "now () -1 detik".

Keuntungan dari skema ini adalah Anda dapat menciptakan kembali "keadaan" entitas logis Anda kapan saja, Anda memiliki riwayat entitas Anda dari waktu ke waktu dan Anda meminimalkan pertengkaran jika "entitas logis" Anda banyak digunakan.

Kerugiannya adalah Anda menyimpan lebih banyak data, dan Anda perlu mempertahankan lebih banyak indeks (paling tidak pada Logical Key + ValidFrom + ValidTo). Indeks pada Kunci Logis + Versi Terbaru sangat mempercepat sebagian besar kueri. Ini juga mempersulit SQL Anda!

Apakah ini layak dilakukan kecuali jika Anda benar-benar perlu mempertahankan sejarah dan memiliki persyaratan untuk menciptakan kembali keadaan entitas Anda pada titik waktu tertentu, itu terserah Anda.

James Anderson
sumber
1

Alasan lain yang memungkinkan untuk memiliki basis data yang tidak dapat diubah adalah untuk mendukung pemrosesan paralel yang lebih baik. Pembaruan yang terjadi rusak dapat mengacaukan data secara permanen, sehingga penguncian harus dilakukan untuk mencegah hal itu, menghancurkan kinerja paralel. Banyak sisipan acara dapat berlangsung dalam urutan apa pun, dan negara bagian paling tidak pada akhirnya akan benar selama semua acara akhirnya diproses. Namun ini sangat sulit untuk dikerjakan dalam praktek dibandingkan dengan melakukan pembaruan basis data sehingga Anda harus benar-benar membutuhkan banyak paralelisme untuk mempertimbangkan melakukan hal-hal dengan cara ini - saya tidak merekomendasikannya.

psr
sumber
0

Penafian: Saya cukup baru di DB: hlm

Karena itu, pendekatan data satelit ini memiliki dampak langsung pada kinerja:

  • Lalu lintas kurang baik di tabel utama
  • Baris kecil yang baik di tabel utama
  • Buruk membutuhkan data satelit berarti pencarian lain diperlukan
  • Buruk ruang lebih banyak ditempati jika semua objek ada di kedua tabel

tergantung pada kebutuhan Anda, Anda dapat menerima ini, atau tidak, tetapi ini tentu saja merupakan hal yang perlu dipertimbangkan.

Matthieu M.
sumber
-1

Saya tidak melihat bagaimana skema Anda dapat disebut "tidak berubah".

Apa yang terjadi ketika nilai yang disimpan dalam tabel tambahan berubah? Sepertinya Anda perlu melakukan pembaruan di meja itu.

Agar database benar-benar tidak berubah, ia perlu dikelola hanya oleh "INSERTS". Untuk ini, Anda memerlukan beberapa metode untuk mengidentifikasi baris "saat ini". Ini hampir selalu berakhir dengan sangat tidak efisien. Anda juga harus menyalin semua nilai sebelumnya yang tidak berubah atas, atau, menyatukan keadaan saat ini dari beberapa catatan saat Anda kueri. Pemilihan baris saat ini biasanya membutuhkan beberapa SQL yang sangat berantakan seperti ( where updTime = (SELECT max(updTime) from myTab where id = ?).

Masalah ini banyak muncul di DataWarehousing di mana Anda harus menyimpan riwayat data dari waktu ke waktu, dan, dapat memilih negara untuk setiap titik waktu tertentu. Solusinya biasanya tabel "dimensional". Namun sementara mereka memecahkan masalah DW "yang merupakan tenaga penjualan Januari lalu". Mereka tidak memberikan keuntungan apa pun yang dikerjakan oleh kelas-kelas yang tidak berubah di Jawa.

Pada catatan yang lebih filosofis; database ada untuk menyimpan "state" (saldo bank Anda, konsumsi listrik Anda, poin brownies Anda di StackOverflow dll.) yang mencoba memunculkan database "stateless" tampaknya merupakan latihan yang agak tidak berguna.

James Anderson
sumber
Untuk satu rekaman, WHERE id = {} ORDER BY updTime DESC LIMIT 1umumnya tidak terlalu tidak efisien.
Izkata
@Izkata - coba letakkan di hte tengah dari tiga tabel bergabung :-)
James Anderson