Inilah kegagalan yang saya lihat berlaku dua kali, dalam dua enjin berbeza. Satu eksport berjalan pada 10:00 dan merekod cap masa ubah suai terakhir tertinggi yang dilihatnya. Satu transaksi yang bermula pada 09:58 masih terbuka, commit pada 10:03 dan membawa cap masa dari saat ia bermula. Eksport seterusnya hanya meminta baris yang lebih baharu daripada 10:00 dan tidak pernah melihatnya. Saiz pemindahan sangat baik dan datanya salah.

Jejaki eksport yang kehilangan satu baris

Ikut urutan peristiwa, bukan SQL. Aplikasi menulis masa ubah suai baris apabila transaksi bermula, bukan apabila ia commit. Pengeksport membaca tanda air jam dinding sementara transaksi itu masih terbuka. Kemudian transaksi itu commit dengan masa ubah suai yang lebih lama daripada tanda air yang disimpan. Kelompok seterusnya pengguna bermula selepas tanda air, jadi baris itu kekal di belakang kursor dan tidak akan dipilih lagi.

Tiada apa-apa merekod ralat, kerana tiada apa-apa gagal. Itulah yang menjadikan kelas pepijat ini mahal: suapan delta pantas, bilangan baris kelihatan munasabah, dan baris yang hilang muncul berminggu-minggu kemudian sebagai tiket perdamaian yang tiada siapa dapat menghasilkan semula.

Nombor jujukan mempunyai bentuk kecacatan yang sama atas sebab lain. ID monoton memberitahu anda urutan nilai diperuntukkan, bukan urutan transaksi di-commit. Transaksi yang mengambil nombor rendah boleh commit selepas transaksi yang mengambil nombor tinggi, jadi kursor berdasarkan urutan peruntukan juga boleh meninggalkan lubang.

Lima janji yang suapan mesti tunaikan

Sebelum memilih pengangkutan, minta kontrak lima klausa daripada sistem sumber. Jika mana-mana klausa tiada, anda mempunyai heuristik, bukan suapan perubahan.

  • Liputan: sisipan, kemas kini dan pemadaman, setiap satu dengan kunci stabil yang diperlukan untuk menggunakannya.
  • Sempadan: apa maksud nilai kursor dan apa yang terkandung dalam kelompok konsisten.
  • Konsistensi: bagaimana jadual berkaitan dibaca tanpa mencampur keadaan sumber yang tidak serasi.
  • Pengekalan: berapa lama pengguna yang terputus boleh menyambung semula dari kedudukan tersimpannya.
  • Permulaan semula: petikan penuh yang disokong apabila kedudukan itu tidak lagi sah.

Mekanisme yang disokong boleh memenuhi kelima-lima. Dokumentasi SQL Server tentang penjejakan perubahan ialah satu contoh terbit konkrit: ia mentakrifkan versi sah minimum, merekod pemadaman serta perubahan, dan menerangkan transaksi petikan yang merangkumi pengesahan, tangkapan versi dan pertanyaan perubahan berkaitan. Ia contoh apa yang patut dituntut daripada sumber, bukan sintaks yang boleh anda tampal dalam enjin lain.

Reka titik semak sebagai bahagian saluran paip

Kedudukan tersimpan pengguna ialah mesin keadaan sebenar, jadi tuliskan sedemikian. Kursor hanya boleh mara melalui aliran kerja yang sudah menggunakan kelompok dan sudah commit transaksi sasaran.

cursor  = durable_checkpoint()          # last fully applied position
batch   = extract(cursor, upper_bound)  # one consistent batch
apply(batch)                            # idempotent at the target
commit()
checkpoint(batch.upper_bound)           # only now

Jika penghantaran gagal di pertengahan jalan, damaikan kelompok yang sama dan bukan mencipta kedudukan sumber baharu. Pengekstrakan semula dengan sempadan atas yang lebih baharu ialah cara penggunaan separa menjadi jurang kekal. Peraturan cermin juga terpakai di sisi lain: penggunaan idempoten di sasaran menghalang pertindihan dan tidak melakukan apa-apa untuk perubahan yang tidak pernah dilihat oleh pengekstrakan.

Pemadaman perlukan rekod, bukan kesimpulan

Membandingkan baris yang masih ada tidak dapat memberitahu pengguna kunci mana yang hilang. Sumber yang tidak pernah merekod pemadaman meninggalkan anda dua pilihan tidak sempurna: menyimpan sejarah kunci cukup lama untuk diff, atau menjalankan perdamaian penuh yang eksplisit mengikut jadual. Kedua-duanya keputusan reka bentuk dengan kos, dan tiada satu wujud melainkan seseorang memilikinya.

Pengekalan ialah keputusan jenis yang sama. Setiap suapan perubahan yang disokong mempunyai tetingkap; nyatakan dalam kontrak dan beri amaran apabila titik semak pengguna menghampirinya. Pengguna yang bangun selepas gangguan dua minggu sepatutnya membaca ralat jelas "permulaan semula diperlukan" dan bukannya menerima kelompok separa secara senyap.

Kemudian ukur sama ada delta itu berbaloi

Kembali membandingkan setiap kunci dan hash kadangkala betul, dan wajar mengetahui kosnya. Anda masih memindahkan maklumat tentang setiap baris, hash tidak memberi anda petikan konsisten merentas jadual, dan skema hash membawa persoalannya sendiri tentang perwakilan dan perlanggaran. Kurang bait dengan sempadan yang boleh disahkan ialah matlamatnya; kurang bait yang menggugurkan perubahan yang sudah di-commit secara senyap sama sekali bukan delta.

Lajur ubah suai terakhir ialah petunjuk. Kursor yang bertahan daripada commit lewat, pemadaman dan gangguan panjang ialah kontrak.

Artikel berkaitan