Di mana InnoDB menyimpan data transaksi sebelum melakukannya?

12

Saya telah melakukan beberapa tes menggunakan READ_COMMITTEDdan READ_UNCOMMITTEDdi rumah, menggunakan teknologi JDBC.

Saya melihat bahwa READ_UNCOMMITTEDsebenarnya dapat membaca data yang tidak dikomit, misalnya data dari beberapa transaksi yang belum berkomitmen (dapat melakukan permintaan-UPDATE).

Pertanyaan

  • Di mana data yang tidak terikat disimpan, sehingga READ_UNCOMMITTEDtransaksi dapat membaca data yang tidak terikat dari transaksi lain?
  • Mengapa READ_COMMITTEDtransaksi tidak dapat membaca data yang tidak dikomit, yaitu melakukan "membaca kotor"? Mekanisme apa yang memberlakukan pembatasan ini?
Shuzheng
sumber

Jawaban:

11

" Di mana data yang tidak terikat disimpan, sedemikian sehingga transaksi READ_UNCOMMITTED dapat membaca data yang tidak terikat dari transaksi lain? "

Versi catatan tanpa komitmen baru (PK berkerumun) diperlakukan sebagai versi "saat ini" dari catatan di halaman. Jadi mereka dapat disimpan di buffer pool dan / atau di tablespace (misalnya tablename.ibd). Transaksi yang kemudian perlu membuat snapshot / tampilan dalam apa pun selain BACA-TIDAK DIKOMITMEN, perlu membuat versi baris sebelumnya (mengikuti daftar riwayat) menggunakan catatan UNDO (disimpan dalam tablespace sistem ). Saat membaca catatan tidak berkomitmen, InnoDB mungkin juga perlu membaca beberapa catatan indeks sekunder yang tidak terikat dari Change Buffer dan menerapkannya sebelum menyajikan catatan kembali ke pengguna.

Perilaku inilah yang dapat membuat rollbacks di InnoDB relatif mahal. Ini adalah faktor besar yang juga dapat menyebabkan masalah kinerja potensial dari transaksi lama yang berjalan yang menyimpan catatan yang diperbarui, karena transaksi tersebut akan memblokir operasi pembersihan dan daftar riwayat versi catatan lama tumbuh, dan catatan UNDO diperlukan untuk membangun kembali versi lama tersebut. on-demand, akan terus tumbuh. Ini memperlambat transaksi baru yang perlu membaca versi yang lebih lama / berkomitmen dari catatan, karena mereka perlu menelusuri daftar sejarah yang lebih lama dan lebih lama - yang merupakan daftar tunggal yang terkait catatan UNDO - dan melakukan lebih banyak pekerjaan untuk merekonstruksi versi lama dari catatan. Jadi Anda akhirnya menggunakan banyak siklus CPU (belum lagi primitif penguncian internal: mutex, rw_locks, semaphores, dll.

Semoga itu masuk akal? :)

Sebagai FYI, di MySQL 5.7 Anda dapat memindahkan tablespace UNDO dan log out dari tablespace sistem , dan membuatnya terpotong secara otomatis. Mereka dapat tumbuh cukup besar jika Anda memiliki transaksi berjalan lama yang mencegah operasi pembersihan, menghasilkan panjang daftar sejarah yang sangat panjang dan terus bertambah. Setelah disimpan di tablespace sistem adalah satu-satunya penyebab paling umum dari file ibdata1 yang besar / berkembang, yang pada gilirannya tidak dapat terpotong / menyusut / disedot untuk kemudian mendapatkan kembali ruang itu.

Matt Lord
sumber
4

Kamu bertanya

di mana data yang tidak terikat disimpan, sehingga transaksi READ_UNCOMMITTED dapat membaca data yang tidak terikat dari transaksi lain?

Untuk menjawab pertanyaan Anda, Anda perlu tahu seperti apa Arsitektur InnoDB.

Gambar berikut dibuat tahun lalu oleh Percona CTO Vadim Tkachenko

Arsitektur InnoDB

Menurut Dokumentasi MySQL tentang Model dan Penguncian Transaksi InnoDB

KOMIT berarti bahwa perubahan yang dibuat dalam transaksi saat ini dibuat permanen dan menjadi terlihat oleh sesi lain. Pernyataan ROLLBACK, di sisi lain, membatalkan semua modifikasi yang dilakukan oleh transaksi saat ini. Baik COMMIT maupun ROLLBACK melepaskan semua kunci InnoDB yang ditetapkan selama transaksi saat ini.

Karena COMMIT dan ROLLBACK mengatur visibilitas data, READ COMMITTED dan READ UNCOMMITTED harus bergantung pada struktur dan mekanisme yang merekam perubahan

  1. Rollback Segments / Undo Space
  2. Ulangi Log
  3. Kesenjangan Mengunci Tabel yang Terlibat

Segmen Rollback dan Undo Space akan tahu seperti apa perubahan data sebelum perubahan diterapkan. Redo Log akan tahu perubahan apa yang harus digulirkan ke depan agar data muncul diperbarui.

Anda juga bertanya

mengapa transaksi READ_COMMITTED tidak dapat membaca data yang tidak dikomit, yaitu melakukan "pembacaan kotor"? Mekanisme apa yang memberlakukan pembatasan ini?

Redo Logs, Undo Space dan Baris yang dikunci ikut bermain. Anda juga harus mempertimbangkan Kolam Penyangga InnoDB (tempat Anda dapat mengukur halaman kotor dengan innodb_max_dirty_pages_pct , innodb_buffer_pool_pages_dirty dan innodb_buffer_pool_bytes_dirty ).

Mengingat hal ini, READ COMMITTED akan tahu data seperti apa yang muncul secara permanen. Oleh karena itu, tidak perlu mencari halaman kotor yang tidak dilakukan. READ COMMITED tidak akan lebih dari sekadar pembacaan kotor yang telah dilakukan. READ UNCOMMITTED akan terus mengetahui baris apa yang harus dikunci dan apa yang harus dilakukan atau dibaca ulang log untuk membuat data terlihat.

Untuk memahami sepenuhnya Penguncian Baris untuk Mengelola Isolasi, baca Model dan Penguncian Transaksi InnoDB

RolandoMySQLDBA
sumber
1
Pertama, terima kasih atas jawaban dan modifikasi posting saya ... Jadi, sebelum KOMIT, perubahan tidak terlihat oleh pengguna sistem lainnya? Di sini pengguna secara harfiah berarti transaksi, bukan? Karena READ UNCOMMITTED dapat membaca data yang tidak dikomit, di mana level isolasi ini membaca data ini? Mungkinkah ada lebih dari satu sumber data yang tidak terikat untuk item data tertentu dalam database? Jika ya, sepotong data yang tidak terikat akan dibaca?
Shuzheng