当前位置:网站首页>Why does the official not recommend using UUID as MySQL primary key
Why does the official not recommend using UUID as MySQL primary key
2022-07-25 04:55:00 【A rookie is a great God】
Preface : stay mysql When designing tables in Chinese ,mysql It is officially recommended not to use uuid Or a snowflake that doesn't continue and doesn't repeat id(long Shape and uniqueness ), It is recommended to increase the primary key continuously id, The official recommendation is auto_increment, So why not recommend uuid, Use uuid What's wrong with it ? In this blog, we will analyze this problem , Explore the internal reasons .
One :mysql And program examples
1.1: Explain the problem , Let's start with three tables , Namely user_auto_key,user_uuid,user_random_key, Represent the auto growing primary keys respectively ,uuid A primary key , Random key A primary key , We'll keep the rest the same . According to the control variable method , We only use different strategies to generate the primary key of each table , And the other fields are exactly the same , Then test the insertion speed and query speed of the table :
** notes : Random here key In fact, it refers to the discontinuity and non repetition calculated by the snowflake algorithm * Irregular * Of id: a string 18 A length of long value
id Auto generate table :

user uuid surface

Random primary key table :

1.2: Theory alone won't do , Go straight to the program , Use spring Of jdbcTemplate In order to implement the additional search test :
Technical framework :springboot+jdbcTemplate+junit+hutool, The principle of the program is to connect to your own test database , Then write the same amount of data in the same environment , So let's analyze that insert Insert time to synthesize its efficiency , In order to achieve the most realistic effect , All the data are randomly generated , Such as name 、 mailbox 、 Addresses are randomly generated , Program uploaded from gitee, The address is at the bottom of the article .
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(" perform sql Time consuming ");
/**
* auto_increment key Mission
*/
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(" Automatic generation key Table task begins ");
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 Time consumed :" + (end1 - start1));
stopwatch.stop();
/**
* uudID Of 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 Of key Table task begins ");
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 Time consumed :" + (over - begin));
stopwatch.stop();
/**
* Random long value 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(" Random long value key Table task begins ");
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(" Random key Tasks take time :" + (end - start));
stopwatch.stop();
String result = stopwatch.prettyPrint();
System.out.println(result);
}
1.3: Program write results
user_key_auto Write results :

user_random_key Write results :

user_uuid Table write results :

1.4: Efficiency test results

In the existing data volume is 130W When : Let's test the insertion again 10w data , See what happens :

You can see in the amount of data 100W Left and right ,uuid At the bottom of insertion efficiency , And added... In the following order 130W The data of ,uudi And then it's plummeting again . The overall efficiency ranking of time occupancy is :auto_key>random_key>uuid,uuid The least efficient , In case of large amount of data , Efficiency has plummeted . So why does this happen ? With questions , Let's talk about this :
Two : Use uuid And self increase id Index structure comparison of
2.1: Use self increasing id The internal structure of

The values of the self increasing primary key are sequential , therefore Innodb Store each record at the end of a record . When the maximum fill factor of the page is reached (innodb The default maximum fill factor is page size 15/16, Will be set aside 1/16 Space for future modify ):
① The next record will be written to the new page , Once the data is loaded in this order , It's going to fill the pages in almost the order of the primary keys , Improved the maximum fill rate of the page , There will be no waste of pages
② The newly inserted row must be next to the original maximum data row ,mysql Location and addressing are fast , There is no additional cost to calculate the position of the new row
③ Reduced page fragmentation and fragmentation
2.2: Use uuid Index internal structure of

because uuid Self increasing of relative order id There are no rules to be said for , The value of the new row does not have to be larger than the value of the previous primary key , therefore innodb You can't always insert new rows at the end of the index , It's about finding new locations for new lines to allocate new space . This process requires a lot of extra work , Data out of order can lead to data scattered , Will lead to the following problems :
①: The target page written is likely to have been flushed to disk and removed from the cache , Or it hasn't been loaded into the cache yet ,innodb Before inserting, you have to find and read the target page from disk into memory , This will lead to a lot of randomness IO
②: Because the writing is out of order ,innodb Have to do frequent page splitting operations , To allocate space for new rows , Page splitting causes a lot of data to be moved , At least three pages need to be modified at a time
③: Due to frequent page splits , The page becomes sparse and filled irregularly , Eventually, the data will be fragmented
We're putting random values (uuid And snowflakes id) Load to cluster index (innodb The default index type ) in the future , Sometimes it needs to be done once OPTIMEIZE TABLE To rebuild tables and optimize page filling , It will take time again .
Conclusion : Use innodb You should insert as much as possible in the auto increment order of the primary key , And try to insert new rows with monotonically increasing cluster key values
2.3: Use self increasing id The shortcomings of
Then use self increasing id No harm at all ? Not at all , Self increasing id There will also be the following problems :
①: Once someone else crawls into your database , According to the database self increment id Get your business growth information , It's easy to analyze your business
②: For high concurrency loads ,innodb When inserting by primary key, there will be obvious lock contention , The upper bound of the primary key will become a hot topic of contention , Because all the insertions happen here , Concurrent inserts can lead to gap lock contention
③:Auto_Increment The lock mechanism will cause the preemption of self increasing lock , There is a certain loss of performance
attach :Auto_increment The lock contention problem of , If you want to improve, you need to tune innodb_autoinc_lock_mode Configuration of
3、 ... and : summary
This blog starts with a question from the beginning , Build a watch to use jdbcTemplate To test different id The generation strategy of large amount of data in the performance of data insertion , Then I analyzed id The mechanism is different in mysql Index structure and advantages and disadvantages of , It explains why uuid And random no repetition id Performance loss in data insertion , Explain the problem in detail . In actual development, it is still based on mysql It's better to use auto increment id,mysql broad and profound , There are still a lot of internal optimization points that we need to learn .
This blog demo Address :https://gitee.com/Yrion/mysqlIdDemo
边栏推荐
- The 6th "Blue Hat Cup" National College Students' Cyber Security Skills Competition writeup
- mitt.js:小型事件发布订阅库
- Unity LOD
- Construction of Seata multilingual system
- Actual combat | record an attack and defense drill management
- 2022-7-18 summary
- 5年经验的大厂测试/开发程序员,怎样突破技术瓶颈?大厂通病......
- Web: compiling big refactoring from 10 to 1
- Understand Huawei's 2018 financial report with one picture
- Novel capture practice
猜你喜欢

Druid connection pool - strong self-study from 0. Those who don't understand Druid can click in. If you know not to click in, you will think I'm wordy

【浅析STM32之GPIO寄存器(CRL/CRH)配置 】
![[sht30 temperature and humidity display based on STM32F103]](/img/43/bbc66ab2d56cfa9dc05d795e8fe456.jpg)
[sht30 temperature and humidity display based on STM32F103]

Druid连接池——从0开始坚强的一点点的自学,Druid一点不懂的可以点进来,懂得别点进来,点进来你会嫌我啰嗦的

Open source summer interview | "after 00" PMC member Bai Zeping

Dark king | analysis of zego low illumination image enhancement technology

GDT,LDT,GDTR,LDTR

Detailed explanation of security authentication of mongodb
![[wechat applet] design and interactive implementation of auction product details page (including countdown and real-time update of bids)](/img/01/42de6280191b9c32a7f37d7727bd4f.png)
[wechat applet] design and interactive implementation of auction product details page (including countdown and real-time update of bids)

2022-7-13 summary
随机推荐
Interpretation and download of the report | ink Tianlun July database industry report, be prepared for danger in times of safety, and safety first
运筹学基础【一】 之 导论
GDT,LDT,GDTR,LDTR
Very clear organization
推荐系统-协同过滤在Spark中的实现
Sony announced the closure of Beijing mobile phone factory! The production line will be moved to Thailand, and the cost can be reduced by half!
How to ensure data consistency between MySQL and redis?
Introduction to CpG control network
Druid连接池——从0开始坚强的一点点的自学,Druid一点不懂的可以点进来,懂得别点进来,点进来你会嫌我啰嗦的
[cloud picture theory] 248 illustrated public network domain name resolution: easy domain name access to websites / mailboxes
自然的状态最好
GBase JDBC 连接数据库异常
Introduction to fundamentals of operations research [1]
【基于stm32f103的SHT30温湿度显示】
How can test / development programmers with 5 years of experience break through the technical bottleneck? Common problems in big factories
Gbase JDBC connection database exception
[CTF learning] steganography set in CTF -- picture steganography
Summary of UPR optimization suggestions of unity
2022-7-18 summary
etcd学习