Tombstone Table vs Flag Dihapus dalam sinkronisasi database & skenario soft-delete

17

Saya perlu melacak item yang dihapus untuk kebutuhan sinkronisasi klien.

Secara umum, apakah lebih baik menambahkan tabel batu nisan dan pemicu yang melacak ketika baris dihapus dari database server - pada dasarnya menambahkan baris baru ke tabel batu nisan dengan data dari item yang dihapus - atau untuk menjaga item dalam tabel asli dan tandai sebagai dihapus, biasanya dengan kolom bit jenis, untuk menunjukkan bahwa baris dihapus dan kolom lain untuk dilacak ketika penghapusan terjadi?

Lorenzo Polidori
sumber

Jawaban:

17

Secara umum lebih baik untuk mengetahui persyaratan khusus dan tidak membuat keputusan desain berdasarkan apa yang paling baik dalam kebanyakan situasi. Entah bisa lebih disukai. Berikut adalah beberapa hal khusus untuk dikumpulkan:

  • Seberapa cepat perlu dihapus?
  • Seberapa cepat un-delete perlu dilakukan?
  • Seberapa sering data yang dihapus akan ditanyakan dan akankah ditanyakan dengan data yang belum dihapus?
  • Seberapa cepat permintaan data yang dihapus perlu?
  • Apakah Anda perlu mempertahankan hanya item atau perubahan yang dihapus juga?
  • Apakah Anda perlu menjaga tabel / indeks pada tabel utama kecil?
  • Teknologi partisi dan / atau perubahan pelacakan apa yang tersedia pada platform basis data?
  • Berapa banyak ruang disk yang tersedia?
  • Akankah penghapusan terjadi dengan cepat atau dalam operasi batch?
Leigh Riffel
sumber
Saya mengerti, ini masalah perdagangan antara persyaratan sistem yang berbeda. Jika saya perlu hapus cepat / hapus-hapus, bendera akan lebih disukai, tetapi jika saya membutuhkan pertanyaan cepat pada item yang dihapus dan juga pada tabel utama dan mungkin saya perlu melacak semua jenis perubahan, pendekatan batu nisan mungkin lebih baik.
Lorenzo Polidori
Kamu mendapatkannya. Bahkan mungkin ada kasus di mana opsi lain lebih disukai. Misalnya, jika Anda hanya perlu penghapusan lunak tersedia selama 24 jam, di Oracle Anda dapat mempertimbangkan untuk mengatur waktu retensi yang dijamin dan kemudian menggunakan kueri kilas balik untuk melihat data yang dihapus.
Leigh Riffel
5

Mungkin Anda harus menggabungkan kedua metode ini dengan sengaja. Kenapa ???

Mari kita gunakan tabel itu (MySQL-dialek)

CREATE TABLE mydata
(
    id int not null auto_increment
    firstname varchar(16) not null,
    lastname varchar(16) not null,
    zipcode char(5) not null,
    ...
    deleted tinyint not null default 0
    KEY (deleted,id),
    KEY (deleted,lastname,firstname,id),
    KEY (deleted,zipcode,id),
    KEY (lastname,firstname),
    KEY (zipcode),
    PRIMARY KEY (id)
);

Harap perhatikan bahwa, dengan pengecualian dari KUNCI UTAMA, setiap indeks yang Anda buat harus didahului dengan deletedbendera dan diakhiri dengan id.

Mari kita buat tabel batu nisan

CREATE TABLE mytomb SELECT id FROM mydata WHERE 1=2;
ALTER TABLE mytomb ADD PRIMARY KEY (id);

Jika meja Anda sudah memiliki deletedbendera, Anda bisa mengisi tabel batu nisan

INSERT INTO mytomb SELECT id FROM mydata WHERE deleted = 1;

OK sekarang data dan nisan sudah disiapkan. Bagaimana Anda melakukan penghapusan?

Katakanlah Anda menghapus setiap orang di kode pos 07305. Anda akan menjalankan yang berikut:

INSERT IGNORE INTO mytomb SELECT id FROM mydata WHERE deleted=0 AND zipcode='07305';
UPDATE mydata SET deleted=1 WHERE deleted=0 AND zipcode='07305';

OK ini sepertinya banyak overhead baik cara Anda melihatnya.

Sekarang, apakah Anda ingin melihat semua data yang dihapus? Berikut ini dua cara berbeda:

  • SELECT * FROM mydata WHERE deleted=1;
  • SELECT B.* FROM mytomb A INNER JOIN mydata B USING (id);

Jika jumlah id di mytomb lebih besar dari 5% dari jumlah baris mydata, itu adalah pemindaian tabel penuh. Jika tidak, pemindaian indeks dengan pencarian untuk setiap baris. Catat tolok ukur apa pun dalam hal ini. Cari menjelaskan rencana.

Sekarang, apakah Anda ingin melihat setiap orang di kode pos 07304? Berikut ini dua cara berbeda:

  • SELECT * FROM mydata WHERE deleted=1 AND zipcode='07304';
  • SELECT A.* FROM mydata A LEFT JOIN mytomb B USING (id) WHERE B.id IS NULL AND A.zipcode='07304'

Bagaimana dengan penghapusan massal? Berikut ini dua cara berbeda:

  • DELETE FROM mydata WHERE deleted=1;
  • DELETE B.* FROM mytomb A INNER JOIN mydata B USING (id); DELETE FROM mytomb;

KESIMPULAN

Sekarang, saya tidak mengatakan untuk tetap menggunakan kedua metode ini. Melakukan hal ini dari waktu ke waktu mengungkapkan metode mana yang lebih cepat dalam hal operabilitas keseluruhan. Anda harus memutuskan tolok ukur mana untuk meminta data langsung, meminta data yang dihapus, dan penghapusan masal paling sesuai untuk Anda.

RolandoMySQLDBA
sumber
Apakah ada keuntungan menggunakan kedua teknik, secara berkelanjutan? Atau apakah Anda menyarankan hanya menggunakannya secara paralel untuk mengevaluasi kinerja, dan kemudian melakukan satu atau yang lain?
Jon of All Trades