MVCC (Multiversion Concurrency Control),多版本并发控制
. Seperti namanya, MVCC melaksanakan pangkalan data 并发控制
melalui pengurusan berbilang versi baris data. Teknologi ini memastikan bahawa operasi 一致性读
dilakukan di bawah tahap pengasingan transaksi InnoDB. Dalam erti kata lain, ia adalah untuk menanyakan beberapa baris yang sedang dikemas kini oleh transaksi lain, dan anda boleh melihat nilai sebelum ia dikemas kini, supaya anda tidak perlu menunggu transaksi lain untuk melepaskan kunci semasa melakukan pertanyaan .
Tiada standard formal untuk MVCC Pelaksanaan MVCC mungkin berbeza dalam DBMS yang berbeza, dan ia tidak digunakan secara universal (anda boleh merujuk kepada dokumentasi DBMS yang berkaitan). Di sini kami menerangkan mekanisme pelaksanaan MVCC dalam InnoDB (enjin storan MySQL lain tidak menyokongnya)
Pelaksanaan MVCC dalam MySQL InnoDB adalah terutamanya untuk menambah baik pangkalan data Prestasi concurrency, gunakan cara yang lebih baik untuk mengendalikan 读-写冲突
, supaya walaupun terdapat konflik baca-tulis, 不加锁
, 非阻塞并发读
boleh dicapai, dan bacaan ini merujuk kepada 快照读
, bukan 当前读
. Bacaan semasa sebenarnya adalah operasi penguncian dan pelaksanaan penguncian pesimis. Intipati MVCC ialah cara menggunakan pemikiran mengunci optimistik.
Bacaan syot kilat juga dipanggil bacaan konsisten dan ia membaca data syot kilat. 不加锁的简单的SELECT都属于快照读
, ialah bacaan tidak menyekat tanpa mengunci; sebagai contoh:
select * from player where ...
Sebab mengapa bacaan syot kilat berlaku adalah berdasarkan pertimbangan untuk meningkatkan prestasi serentak Berdasarkan MVCC, ia mengelakkan operasi mengunci dan mengurangkan overhed dalam banyak kes.
Memandangkan ia berdasarkan berbilang versi, petikan yang dibaca mungkin tidak semestinya membaca versi terkini data, tetapi mungkin versi sejarah sebelumnya.
Premis bacaan syot kilat ialah tahap pengasingan bukan tahap siri bacaan syot kilat pada tahap siri akan merosot kepada bacaan semasa.
Bacaan semasa membaca versi terkini rekod (data terkini, bukan versi sejarah data semasa membaca, ia juga perlu memastikan yang lain). urus niaga serentak tidak boleh mengubah suai rekod semasa, rekod yang dibaca akan dikunci. SELECT terkunci, atau penambahan, pemadaman atau pengubahsuaian data akan menghasilkan bacaan semasa. Contohnya:
Kami tahu bahawa terdapat 4 tahap pengasingan, mungkin terdapat tiga masalah konkurensi:
Dalam MysQL, tahap pengasingan lalai ialah bacaan berulang, yang boleh menyelesaikan bacaan kotor dan bacaan tidak boleh berulang Jika kita melihat masalah membaca hanya dari sudut definisi, ia tidak menyelesaikan masalah membaca hantu. Jika kita ingin menyelesaikan masalah bacaan hantu, kita perlu menggunakan serialisasi, iaitu, untuk meningkatkan tahap pengasingan ke tahap tertinggi, tetapi ini akan mengurangkan keupayaan konkurensi transaksi pangkalan data dengan ketara.
MVCC boleh menyelesaikan masalah bacaan tidak berulang dan bacaan hantu melalui penguncian optimistik dan bukannya menggunakan mekanisme penguncian Ia boleh menggantikan kunci peringkat baris dalam kebanyakan kes dan mengurangkan overhed sistem.
Mari semak rantaian versi log buat asal Untuk jadual yang menggunakan enjin storan InnoDB, indeks Kluster pengagregatannya direkodkan mengandungi dua lajur tersembunyi yang diperlukan.
trx_id: Setiap kali transaksi menukar rekod indeks berkelompok, id transaksi transaksi akan diberikan kepada lajur tersembunyi trx_id. roll_pointer: Setiap kali rekod indeks berkelompok diubah suai, versi lama akan ditulis ke log batal Kemudian lajur tersembunyi ini bersamaan dengan penunjuk yang melaluinya maklumat sebelum rekod boleh ditemui.
Pelaksanaan MVCC bergantung pada: Medan tersembunyi, Buat asal Log, Pandangan Baca
Dalam mekanisme MVCC, pasangan transaksi berbilang Mengemas kini rekod baris yang sama akan menghasilkan berbilang petikan sejarah dan petikan sejarah ini disimpan dalam Log Buat Asal. Jika transaksi ingin menanyakan rekod baris ini, versi rekod baris yang manakah perlu dibaca pada masa ini, ReadView perlu digunakan, yang membantu kami menyelesaikan masalah keterlihatan baris.
Apabila transaksi menggunakan mekanisme MVCC untuk melaksanakan operasi baca syot kilat, paparan baca akan dijana, iaitu ReadView. Apabila transaksi dimulakan, petikan semasa sistem pangkalan data akan dijanakan InnoDB membina tatasusunan untuk setiap transaksi untuk merekod dan mengekalkan ID transaksi aktif semasa sistem ("aktif" merujuk kepada yang telah dimulakan tetapi. belum diserahkan ).
Gunakan READ UNCOMMITTED
urus niaga peringkat pengasingan kerana anda boleh membaca rekod yang diubah suai oleh urus niaga tanpa komitmen, anda hanya boleh membaca versi terkini rekod secara langsung
Menggunakan SERIALIZABLE
transaksi peringkat pengasingan, InnoDB memerlukan penguncian untuk mengakses rekod
Menggunakan READ COMMITTED
dan REPEATABLE READ
transaksi peringkat pengasingan mesti memastikan akses baca Rekod yang diubah suai. Jika transaksi lain telah mengubah suai rekod tetapi belum menyerahkannya, versi terkini rekod tidak boleh dibaca secara langsung masalah utama yang perlu diselesaikan oleh ReadView. 已经提交了的事务
Jika nilainya daripada atribut trx_id versi yang diakses adalah sama dengan nilai
dalam ReadView, ini bermakna transaksi semasa mengakses rekodnya sendiri yang diubah suai, jadi versi ini boleh diakses oleh transaksi semasa 🎜>Jika nilai atribut trx_id versi yang diakses adalah kurang daripada nilai dalam ReadView, ini menunjukkan bahawa transaksi yang menjana versi ini telah dilakukan sebelum transaksi semasa menghasilkan ReadView, jadi versi ini boleh diakses oleh transaksi semasa 🎜>
Jika nilai atribut trx_id versi yang diakses adalah lebih besar daripada atau sama dengan nilai Jika ia ada, ini bermakna transaksi yang menghasilkan versi ini masih aktif apabila ReadView dibuat, dan versi ini tidak boleh diakses menjana versi ini apabila ReadView telah dibuat telah dilakukan, dan versi ini boleh diakses 4.4 proses operasi keseluruhan MVCC creator_trx_id
Selepas memahami konsep ini, mari kita lihat bagaimana. sistem menemuinya melalui MVCC apabila menanyakan rekod: up_limit_id
1. Mula-mula dapatkan nombor versi transaksi, iaitu ID transaksi;low_limit_id
up_limit_id
low_limit_id
trx_ids
3. Tanya data yang diperoleh dan kemudian bandingkan dengan nombor versi transaksi dalam ReadView;
4 Jika ia tidak memenuhi peraturan Readview, anda perlu mendapatkan petikan sejarah daripada Undo Log ;
Dalam InnoDB, MVCC membaca data melalui Undo Log + Read View menyimpan petikan sejarah dan peraturan Read View membantu kami menentukan sama ada versi data semasa boleh dilihat.
Contoh
Andaikan itu hanya terdapat satu rekod yang disisipkan dalam jadual pelajar oleh
untuk transaksi:
MVCC hanya boleh digunakan dalam READ Berfungsi di bawah dua tahap pengasingan: KOMITED dan BACA BOLEH DIULANG. Seterusnya, mari kita lihat perbezaan dalam masa yang dipanggil untuk menjana Readview antara dan .
5.1 BACA KOMITED
Kini terdapat dua transaksi dengan ID transaksi 10 dan 20 sedang dilaksanakan: Penjelasan: Pelaksanaan transaksi Semasa proses, hanya apabila rekod sebenarnya diubah suai buat kali pertama (seperti menggunakan penyata INSERT, DELETE, UPDATE), ID transaksi yang berasingan akan diberikan dan ID transaksi ini akan ditambah. Itulah sebabnya kami mengemas kini beberapa rekod dalam jadual lain dalam transaksi 2 untuk membenarkannya memberikan id transaksi. Pada masa ini, senarai pautan versi yang diperolehi oleh rekod dengan id 1 dalam jadual pelajar adalah seperti berikut: Andaikan sekarang Transaksi menggunakan tahap pengasingan READ COMMITED memulakan pelaksanaan: Proses pelaksanaan SELECT1 ini adalah seperti berikut: Langkah 1∶ akan mula-mula menjana kepada transaksi kepada Pada masa ini, rantai versi rekod dengan id 1 dalam table student is Ia kelihatan seperti ini: seperti berikut: Proses pelaksanaan SELECT2 ini adalah seperti berikut: Langkah 1∶Apabila melaksanakan pernyataan SELECT, akan terdapat satu lagi ralat Hasilkan ReadView secara berasingan Kandungan senarai trx_ids ReadView ialah [20], up_limit_id ialah 20, low_limit_id ialah 21 dan creator_trx_id ialah 0. Di bawah tahap pengasingan: Sebagai contoh, terdapat dua transaksi dengan ID transaksi 10 dan 20 sedang dilaksanakan dalam sistem: 此刻,表student中id为1的记录得到的版本链表如下所示: 假设现在有一个使用REPEATABLE READ隔离级别的事务开始执行: 此时执行过程与read committed相同 然后再到刚才使用REPEATABLE READ隔离级别的事务中继续查找id为1的记录,如下: 这个SELECT2的执行过程如下: 步骤1:因为当前事务的隔离级别为REPEATABLE READ,而之前在执行SELECT1时已经生成过ReadView了,所以此时直接复用之前的ReadView,之前的ReadView的trx_ids列表的内容就是[10,20],up_limit_id为10, low_limit_id为21 , creator_trx_id为0。 假设现在表student中只有一条数据,数据内容中,主键id=1,隐藏的trx_id=10,它的undo log如下图所示。 假设现在有事务A和事务B并发执行,事务A的事务id为20,事务B的事务id为30。 在开始查询之前,MySQL会为事务A产生一个ReadView,此时ReadView的内容如下: 因为表student只有一条符合条件 where id>=1 的数据,所以会被查询出来。然后根据ReadView机制,发现该行数据的trx_id=10,小于事务A的ReadView里up_limit_id,这表示这条数据是事务A开启之前,其他事务就已经提交了的数据,因此事务A可以读取到。 结论:事务A的第一次查询,能读取到一条数据,id=1。 步骤2∶接着事务B(trx_id=30),往表student中新插入两条数据,并提交事务。 此时表student中就有三条数据了,对应的undo如下图所示: Langkah 3∶ Kemudian transaksi A memulakan pertanyaan kedua Mengikut peraturan tahap pengasingan bacaan boleh berulang, transaksi A tidak akan menjana semula ReadView pada masa ini. Pada masa ini, tiga keping data dalam jadual pelajar semuanya memenuhi syarat di mana id>=1, jadi mereka akan ditemui dahulu. Kemudian mengikut mekanisme ReadView, ia dinilai sama ada setiap bahagian data boleh dilihat oleh transaksi A. Kesimpulan: Pertanyaan kedua transaksi terakhir A hanya boleh menanyakan data dengan id=1. Ini adalah sama seperti hasil pertanyaan pertama transaksi A, jadi tiada fenomena bacaan hantu Oleh itu, di bawah tahap pengasingan berulang MySQL, tidak ada masalah membaca hantu. Atas ialah kandungan terperinci Analisis contoh MVCC kawalan penukaran berbilang versi MySQL. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!事务id
8
ReadView
apabila melaksanakan pernyataan SELECT Kandungan senarai trx_ids
ReadView ialah [10, 20], up_limit_id
ialah 10
. , dan low_limit_id
ialah 21
, creator_trx_id
ialah 0
.
Langkah 2: Pilih rekod yang boleh dilihat daripada rangkaian versi Seperti yang dapat dilihat daripada rajah, kandungan lajur name
versi terkini ialah '王五'
dan nilai trx_id
versi ini ialah <. 🎜>, dalam senarai trx_ids dalam, jadi ia tidak memenuhi keperluan keterlihatan dan melompat ke versi seterusnya mengikut roll_pointer. 10
Langkah 3: Kandungan lajur
versi seterusnya ialah name
Nilai '李四'
versi ini juga trx_id
dan juga dalam senarai 10
, jadi ia tidak. memenuhi keperluan Teruskan melompat ke versi seterusnya. trx_ids
Langkah 4: Kandungan lajur
dalam versi seterusnya ialah name
dan nilai ‘张三'
versi ini ialah trx_id
, iaitu kurang daripada nilai up_limit_id 10 dalam ReadView, jadi versi ini memenuhi keperluan Akhirnya Versi yang dikembalikan kepada pengguna ialah rekod yang nama lajurnya ialah "Zhang San". Selepas 8
id
: 10
事务id
Kemas kini rekod dengan 20
student
dalam jadual id
: 1
Langkah 2:Pilih rekod yang boleh dilihat daripada rangkaian versi Seperti yang dapat dilihat daripada rajah, kandungan nama lajur versi terkini ialah "Song Ba", dan nilai tr×_id. daripada versi ini ialah 20, berada dalam senarai trx_ids, jadi ia tidak memenuhi keperluan keterlihatan dan melompat ke versi seterusnya mengikut roll.pointer.
Langkah 3∶Kandungan nama lajur versi seterusnya ialah ’Qian Qi’ Nilai trx_id versi ini ialah 20, yang juga terdapat dalam senarai trx_ids, jadi ia tidak. memenuhi keperluan Teruskan melompat ke versi seterusnya. Langkah 4: Kandungan nama lajur versi seterusnya ialah "王五". Nilai trx_id versi ini ialah 10, iaitu kurang daripada nilai up_limit.id 20 dalam ReadView, jadi versi ini memenuhi keperluan , dan akhirnya kembali Versi yang diberikan kepada pengguna ialah rekod yang nama lajurnya ialah "王五".
Secara analogi, jika rekod dengan ID transaksi 20 juga diserahkan kemudian, apabila rekod dengan nilai ID 1 dalam pelajar jadual disoal semula dalam transaksi menggunakan tahap pengasingan READ CONMMITTED, hasil yang diperoleh ialah "Song Ba" ;, kami tidak akan menganalisis proses tertentu.
步骤2:然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列name的内容是’宋八’trx_id值为20,在trx_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
步骤3:下一个版本的列name的内容是’钱七’,该版本的trx_id值为20,也在trx_ids列表内合要求,继续跳到下一个版本。
步骤4:下一个版本的列name的内容是’王五’,该版本的trx_id值为10,而trx_ids列表中是包含值为10的事务id的,所以该版本也不符合要求,同理下一个列name的内容是’李四’的版本也不符合要求。继续跳到下个版本。
步聚5∶下一个版本的列name的内容是’张三’,该版本的trx_id值为80,小于Readview中的up_limit_id值10,所以这个版本是符合要求的,最后返回给用户的版本就是这条列c为‘张三’的记录。
两次SELECT查询得到的结果是重复的,记录的列c值都是’张三’,这就是可重复读的含义。如果我们之后再把事务id为20的记录提交了,然后再到刚才使用REPEATABLE READ隔离级刷的事务中继续查找这个id为1的记录,得到的结果还是’张三’,具体执行过程大家可以自己分析一下。5.3 如何解决幻读
步骤1:事务A开始第一次查询数据,查询的SQL语句如下。select * from student where id > 1;
trx_ids=[20, 30 ] ,up_limit_id=20 , low_limit_id=31 , creator_trx_id=20。
insert into student(id,name) values(2,'李四');
insert into student(id,name) values(3,'王五');
1) Pertama sekali, data dengan id=1, seperti yang dinyatakan sebelum ini, boleh dilihat oleh transaksi A.
2) Kemudian terdapat data dengan id=2, dan trx_id=30nya Pada masa ini, transaksi A mendapati bahawa nilai ini adalah antara up_limit_id dan low_limit_id, jadi adalah perlu untuk menentukan sama ada 30 berada dalam tatasusunan trx_ids. . Memandangkan trx_ids=[20,30] transaksi A, dalam tatasusunan, ini bermakna data dengan id=2 telah diserahkan oleh transaksi lain bermula pada masa yang sama dengan transaksi A, jadi data ini tidak dapat dilihat oleh transaksi A. .
3) Begitu juga, trx_id data ini dengan id=3 juga adalah 30, jadi ia tidak dapat dilihat oleh transaksi A.