Rumah >pangkalan data >tutorial mysql >Mari kita bincangkan mengapa MySQL tidak boleh menggunakan uuid sebagai kunci utama
Artikel ini memberi anda pengetahuan yang berkaitan bahawa MySQL tidak boleh menggunakan uuid sebagai kunci utama MySQL secara rasmi mengesyorkan untuk tidak menggunakan uuid atau ID kepingan salji tidak berterusan dan tidak berulang, tetapi mengesyorkan ID kunci utama yang meningkat sendiri secara berterusan adalah auto_increment, maka mengapa tidak disyorkan untuk menggunakan uuid. Saya harap ia akan membantu semua orang.
Kata Pengantar
Apabila mereka bentuk jadual dalam mysql, mysql secara rasmi mengesyorkan untuk tidak menggunakan uuid atau tidak Berterusan ID kepingan salji tidak berulang (berbentuk panjang dan unik, kenaikan mesin tunggal) disyorkan, tetapi ID kunci utama yang meningkat sendiri secara berterusan disyorkan adalah auto_increment, jadi mengapa tidak disyorkan untuk menggunakan uuid? keburukan menggunakan uuid?
1. MySQL dan contoh program
1.1 Untuk menerangkan masalah ini, mari buat tiga jadual
ialah pengguna_auto_key, user_uuid, user_random_key masing-masing, yang mewakili kunci utama yang berkembang secara automatik, uuid digunakan sebagai kunci utama,
kunci rawak digunakan sebagai kunci utama, dan kami memastikan yang lain tidak berubah sama sekali .
Menurut Untuk kaedah pembolehubah kawalan, kami hanya menjana kunci utama setiap jadual menggunakan strategi yang berbeza, manakala medan lain adalah sama, dan kemudian menguji kelajuan sisipan dan kelajuan pertanyaan jadual:
Nota: Kunci rawak di sini sebenarnya Merujuk kepada ID terputus, tidak berulang dan tidak teratur yang dikira menggunakan algoritma kepingan salji: rentetan nilai panjang 18-bit
1.2 Teori sahaja tidak mencukupi, pergi terus ke program dan gunakan jdbcTemplate spring untuk melaksanakan ujian pemeriksaan tambahan. :
Rangka kerja teknikal: springboot jdbcTemplate junit hutool, program Prinsipnya adalah untuk menyambung pangkalan data ujian anda sendiri, dan kemudian tulis jumlah data yang sama dalam persekitaran yang sama untuk menganalisis masa sisipan untuk menganalisisnya secara menyeluruh kecekapan. Untuk mencapai kesan yang paling realistik, semua data dijana secara rawak Contohnya, nama, e-mel dan alamat semuanya dijana secara rawak.
package com.wyq.mysqldemo; import cn.hutool.core.collection.CollectionUtil; import com.wyq.mysqldemo.databaseobject.UserKeyAuto; import com.wyq.mysqldemo.databaseobject.UserKeyRandom; import com.wyq.mysqldemo.databaseobject.UserKeyUUID; import com.wyq.mysqldemo.diffkeytest.AutoKeyTableService; import com.wyq.mysqldemo.diffkeytest.RandomKeyTableService; import com.wyq.mysqldemo.diffkeytest.UUIDKeyTableService; import com.wyq.mysqldemo.util.JdbcTemplateService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.util.StopWatch; import java.util.List; @SpringBootTest class MysqlDemoApplicationTests { @Autowired private JdbcTemplateService jdbcTemplateService; @Autowired private AutoKeyTableService autoKeyTableService; @Autowired private UUIDKeyTableService uuidKeyTableService; @Autowired private RandomKeyTableService randomKeyTableService; @Test void testDBTime() { StopWatch stopwatch = new StopWatch("执行sql时间消耗"); /** * auto_increment key任务 */ final String insertSql = "INSERT INTO user_key_auto(user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?)"; List<UserKeyAuto> insertData = autoKeyTableService.getInsertData(); stopwatch.start("自动生成key表任务开始"); long start1 = System.currentTimeMillis(); if (CollectionUtil.isNotEmpty(insertData)) { boolean insertResult = jdbcTemplateService.insert(insertSql, insertData, false); System.out.println(insertResult); } long end1 = System.currentTimeMillis(); System.out.println("auto key消耗的时间:" + (end1 - start1)); stopwatch.stop(); /** * uudID的key */ final String insertSql2 = "INSERT INTO user_uuid(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)"; List<UserKeyUUID> insertData2 = uuidKeyTableService.getInsertData(); stopwatch.start("UUID的key表任务开始"); long begin = System.currentTimeMillis(); if (CollectionUtil.isNotEmpty(insertData)) { boolean insertResult = jdbcTemplateService.insert(insertSql2, insertData2, true); System.out.println(insertResult); } long over = System.currentTimeMillis(); System.out.println("UUID key消耗的时间:" + (over - begin)); stopwatch.stop(); /** * 随机的long值key */ final String insertSql3 = "INSERT INTO user_random_key(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)"; List<UserKeyRandom> insertData3 = randomKeyTableService.getInsertData(); stopwatch.start("随机的long值key表任务开始"); Long start = System.currentTimeMillis(); if (CollectionUtil.isNotEmpty(insertData)) { boolean insertResult = jdbcTemplateService.insert(insertSql3, insertData3, true); System.out.println(insertResult); } Long end = System.currentTimeMillis(); System.out.println("随机key任务消耗时间:" + (end - start)); stopwatch.stop(); String result = stopwatch.prettyPrint(); System.out.println(result); }
1.3 Keputusan penulisan program
boleh dilihat Apabila jumlah data adalah kira-kira 100W, kecekapan sisipan uuid berada di bahagian bawah, dan 130W data ditambah dalam urutan seterusnya, dan masa uudi menjunam semula.
Kedudukan kecekapan keseluruhan penggunaan masa ialah: auto_key>random_key>uuid, uuid mempunyai kecekapan paling rendah Apabila jumlah data adalah besar, kecekapan menjunam. Jadi mengapa ini berlaku? Dengan keraguan, mari kita bincangkan isu ini:
2. Perbandingan struktur indeks menggunakan uuid dan id penambahan automatik
2.1. Gunakan struktur dalaman id penambahan automatik
Nilai kunci utama penambahan automatik adalah berurutan, jadi Innodb menyimpan setiap rekod selepas rekod . Apabila faktor isian maksimum halaman dicapai (faktor isian maksimum lalai InnoDB ialah 15/16 daripada saiz halaman, 1/16 ruang akan ditinggalkan untuk pengubahsuaian masa hadapan):
①Rekod seterusnya akan Apabila menulis ke halaman baharu, setelah data dimuatkan dalam susunan ini, halaman kunci utama akan diisi dengan rekod yang hampir berurutan, meningkatkan kadar pengisian maksimum halaman dan tidak akan ada pembaziran halaman
② Baris yang baru dimasukkan pasti akan berada dalam baris seterusnya bagi baris data asal terbesar dan pengalamatan adalah sangat pantas, dan tidak akan ada penggunaan tambahan untuk mengira kedudukan baris baharu
. ③ Kurangkan pemisahan halaman dan pemecahan Penjanaan
2.2 Gunakan struktur dalaman indeks uuid
kerana uuid tidak mempunyai apa-apa berbanding dengan. id auto-incrementing berurutan Sebagai peraturan, nilai baris baharu tidak semestinya lebih besar daripada nilai kunci utama sebelumnya, jadi innodb tidak boleh sentiasa memasukkan baris baharu ke penghujung indeks, tetapi perlu mencari yang baharu kedudukan yang sesuai untuk baris baru untuk memperuntukkan ruang baru.
Proses ini memerlukan banyak operasi tambahan Data yang tidak teratur akan membawa kepada pengedaran data yang berselerak, yang akan membawa kepada masalah berikut:
①Halaman sasaran bertulis mungkin telah dimuat semula ke. pada cakera dan dialih keluar daripada cache, atau belum dimuatkan ke dalam cache, innodb perlu mencari dan membaca halaman sasaran dari cakera ke dalam memori sebelum memasukkan, yang akan menyebabkan banyak IO rawak
②Oleh kerana penulisan kehabisan pesanan, innodb perlu melakukan operasi pemisahan halaman dengan kerap untuk memperuntukkan ruang untuk baris baharu menyebabkan pemisahan halaman mengalihkan sejumlah besar data, dan sekurang-kurangnya tiga halaman perlu diubah suai untuk sisipan
.③Disebabkan pemisahan halaman yang kerap, halaman akan menjadi jarang dan diisi secara tidak teratur, akhirnya membawa kepada pemecahan data
Memuatkan nilai rawak (uuid dan id kepingan salji) ke dalam kelompok Selepas pengindeksan (jenis indeks lalai bagi innodb), kadangkala anda perlu melakukan OPTIMEIZE TABLE untuk membina semula jadual dan mengoptimumkan pengisian halaman, yang akan mengambil masa tertentu.
Kesimpulan: Apabila menggunakan innodb, anda harus memasukkan sebanyak mungkin dalam susunan kunci utama yang semakin meningkat, dan cuba gunakan nilai kunci pengelompokan yang semakin monoton untuk memasukkan baris baharu
2.3. Keburukan menggunakan ID meningkat sendiri
Jadi tidak ada keburukan sama sekali dalam menggunakan ID meningkat sendiri? Tidak, ID yang meningkat sendiri juga akan mengalami masalah berikut:
① Setelah orang lain merangkak pangkalan data anda, mereka boleh mendapatkan maklumat pertumbuhan perniagaan anda berdasarkan ID pangkalan data yang meningkat sendiri dan ia mudah untuk dianalisis anda Syarat operasi
② Untuk beban serentak yang tinggi, innodb akan menyebabkan pertikaian kunci yang jelas apabila memasukkan mengikut kekunci utama Sempadan atas kunci utama akan menjadi tempat panas untuk pertengkaran, kerana semua sisipan berlaku dalam Di sini , pemasukan serentak akan membawa kepada persaingan kunci celah
③Mekanisme kunci kenaikan_Auto akan menyebabkan rampasan kunci kenaikan automatik, dengan kehilangan prestasi tertentu
Lampiran: Masalah pertikaian kunci_kenaikan automatik, jika ia perlu diperbaiki Menala konfigurasi innodb_autoinc_lock_mode
3. Ringkasan
Blog ini mula-mula bermula dengan bertanya soalan pada permulaan, mencipta jadual dan menggunakan jdbcTemplate untuk menguji berbeza Strategi penjanaan id berfungsi dengan baik dalam memasukkan data sejumlah besar data, dan kemudian menganalisis mekanisme id yang berbeza dalam struktur indeks dan kelebihan dan kekurangan mysql, dan menerangkan secara mendalam mengapa uuid dan id tidak berulang rawak mempunyai kehilangan prestasi dalam sisipan data, secara terperinci menjelaskan masalahnya.
Dalam pembangunan sebenar, sebaiknya gunakan ID yang meningkat sendiri mengikut cadangan rasmi mysql adalah luas dan mendalam, dan terdapat banyak perkara dalaman yang patut dioptimumkan yang perlu kita pelajari.
Pembelajaran yang disyorkan: tutorial video mysql
Atas ialah kandungan terperinci Mari kita bincangkan mengapa MySQL tidak boleh menggunakan uuid sebagai kunci utama. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!