大厂面试题!MySQL为啥不能用UUID做主键?转载

原创
小哥 3年前 (2022-10-17) 阅读数 111 #大杂烩

作者:Yrion

来源:cnblogs.com/wyq178/p/12548864.html

大家好,我是菜鸟兄弟!大家好,我是菜鸟兄弟!大家好,我是菜鸟兄弟!大家好,我是菜鸟兄弟!

在采访大型工厂时,尤其是后端开发人员MYSQL这是一个必问的链接!这是一个问题,想一想,你能不看答案就回答它吗?


前言

在mysql在中设计表时在中设计表当在中设计表时在,mysql官方推荐不要使用,官方推荐不要使用,官方推荐不要使用uuid或不连续不重复的雪花或不连续不重复的雪花id(long单机增塑独特、单机增塑独特),相反,我们建议使用连续的自我递增主键id,官方推荐是官方推荐auto_increment,为什么不推荐使用呢?为什么不推荐使用呢uuid,使用uuid到底有什么不利因素呢?这到底有什么害处呢?这有什么不好的?有什么害处呢?

在这篇博客中,我们将分析这个问题,探索其内在原因。探究其内在原因。探究这一现象的内在原因。探究其中的内在原因。

此博客的目录此博客的目录

  • mysql程序实例

  • 使用uuid和自增id标引结构比较标引结构比较标引结构比较

  • 总结


一、mysql以及程序示例和程序示例以及程序示例

1.1.阐明这个问题澄清这个问题,让我们从创建三个表开始让我们首先创建三个表让我们从创建三个表开始

分别是user_auto_key,user_uuid,user_random_key,分别表示自动增长的主键,uuid作为主键,随机key作为主键,我们保持完全相同的东西,保持完全相同的东西,除了那个,我们保持完全相同.

根据控制变量方法根据控制变量方法根据控制变量方法,我们只使用不同的策略生成每个表的主键,和其他字段完全相同,然后测试表的插入速度和查询速度。

注:这里是随机数key实际上,这意味着使用雪花算法来计算前后不连续的非重复不规则id:一串18位长度的long值

id自动生成表格。自动生成表。自动生成的表。自动生成的表。

用户uuid表

随机主键表。随机主键表。随机主键表。

1.2.光有理论是不行的,光有理论是不够的,光有理论是不行的,直接进入程序直接进入程序,使用spring的jdbcTemplate实施增量检查测试。实施加性复核试验。实施增量搜索测试。以实施增量测试。

技术框架。技术框架。技术框架。springboot+jdbcTemplate+junit+hutool,该程序的原理是连接到您自己的测试数据库,然后在相同的环境中写入相同数量的数据进行分析insert插入的时间要综合其效率,才能达到最真实的效果,所有数据都是随机生成的,如姓名、电子邮件和地址都是随机生成的。另外,搜索公共号码Java后台堆叠回复《私事》,即可获得惊喜大礼包。

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 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 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 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.程序编写结果程序编写结果

user_key_auto写入结果。写入结果。写入结果。正在写结果。

user_random_key写入结果。写入结果。写入结果。正在写结果。

user_uuid表写入结果。写入结果。写入结果。正在写结果。

1.4.效率测试结果效率测试结果效率测试结果

在现有数据量的情况下,现有数据量为,可用的数据量与现有数据量为130W时间:让我们通过插入时间再次测试:让我们通过插入时间再次测试:让我们再次测试以插入10w数据,看看会发生什么。数据,看看会发生什么。

可以看出,在数据量中,可以从数据量中看出其中的数据量100W大约在大约的时间,uuid插入效率的底部按倒序填充和添加130W的数据,uudi时间又一落千丈了。分机。 接私活儿

分时使用率可达到的总体效率排名为auto_key>random_key>uuid,uuid效率最低,在数据量较大的情况下,效率直线下降。那么为什么会出现这种现象呢?带着这个问题,让我们来探讨这个问题。让我们来探讨这个问题。让我们来探讨这个问题。让我们来探讨一下这个问题。


二、使用uuid和自增id标引结构比较标引结构比较标引结构比较

2.1.使用自增id内部结构中的内部结构

自增主键的值是连续的,所以Innodb将每条记录存储在记录之后。当达到页面的最大填充系数时(innodb默认的最大填充系数是页面大小15/16,会留出1/16为将来保留的空间为将来保留的空间为以后保留的空间     修改):

①将下一条记录写入新页,以这种顺序加载数据后,主键页将以近乎连续的顺序填充记录,从而提高最大页填充率而不会浪费页

②新插入的行必须位于原始最大数据行的下一行,mysql定位和寻址速度很快,不需要额外计算新行的位置

(3)减少分页和产生碎片

2.2.使用uuid索引的内部结构

因为uuid自我递增相对次序自我递增相对次序自我递增相对递增次序id它没有模式可循。没有规则可以说没有规则可以这么说,新行的值不必大于前一个主键的值,所以innodb不能总是在索引的末尾插入新行,相反,需要通过为新行找到新的合适位置来分配新空间。

这一过程需要大量的额外操作,而数据的非顺序性将导致数据分布分散,这将导致以下问题。

①写入的目标页可能已刷新到磁盘并从缓存中删除,或尚未加载到缓存中。innodb在插入之前,必须找到目标页并将其从磁盘读取到内存中,这将导致大量随机IO

②,因为写是无序的,因为②是无序的,因为②是无序的,所以②是无序的,innodb不得不做频繁的分页操作不得不做频繁的分页操作不得不做频繁的分页操作,为了给新行分配空间以便为新行分配空间,页面拆分会导致移动大量数据,需要在一次插入中至少修改三个页面

(Iii)由于频繁的页面拆分,页面变得稀疏,填充不规律,最终导致数据碎片

在放置随机值之后(放置随机值之后(放置随机值之后)uuid和雪花id加载到聚集索引)加载到聚集索引)加载到聚集索引(innodb默认索引类型默认索引类型)以后,有时需要做一次,有时需要做一次,有时需要做一次OPTIMEIZE TABLE重建表格并优化页面填充,这将再次需要一些时间消耗。

使用结论:使用结论innodb新行应尽可能以主键的自增顺序插入,并尽可能使用聚集键的单调递增的值

2.3.使用自增id的缺点

然后使用自增id它是完全无害的吗?不完全是,因为增加了id也可能会有几个问题。也可能会有几个问题。还会有几个问题。

①一旦有人爬行您的数据库①一旦有人爬行您的数据库①一旦其他人爬行您的数据库①一旦其他人爬行您的数据库,将有可能根据id获取有关您的业务增长的信息并轻松分析您的运营

②用于高并发负载,②用于高并发负载,innodb按主键插入会导致严重的锁争用,主键的上界成为争用的热点,因为所有插入都发生在这里,而并发插入可能会导致间隙锁争用

③Auto_Increment锁定机制可能会导致自动增加的锁抢夺,有些性能损失有些性能损失一些性能损失

附:Auto_increment锁混乱问题,如果要改进它,就需要对其进行调整innodb_autoinc_lock_mode的配置


三、总结

这个博客从开场白开始这个博客从开场白开始这个博客从开场白开始,构建以使用构建使用表构建以使用表jdbcTemplate去测试不同的去测试不同的id生成策略在大数据量数据插入性能上的应用,并对其进行了分析id这些机制的不同之处在于mysql索引结构和优缺点,深入解释为什么uuid随机不重复和随机不重复、随机不重复和随机不重复id详细说明了数据插入过程中的性能损失。

在实际开发中或根据在实际开发中或在mysql官方的建议是最好使用自我增加的id,mysql国际收支的深度和广度是巨大的,有许多内在的点需要优化,我们需要学习。

机器人公众号已经上线,欢迎来到骚扰

推荐阅读:
入门: 最完整的零基学习最全面的零基学习最完整的零基学习Python的问题  | 从零开始学习从零基础学习从零基础学习8个月的Python  | 实战项目 |学Python这是捷径,这是捷径,这是捷径
干货:爬行豆瓣短评,电影《后来的我们》 | 38年NBA最佳球员分析最佳球员分析 |   从万众期待到口碑惨败!唐探3令人失望  | 笑新伊田图龙记笑新伊田图龙记笑新伊田图龙记 | 谜语之王回答灯谜之王灯谜之王谜语之王 |用Python人山人海素描图人山人海素描图人山人海 Dishonor太火了,我用机器学习做了一个迷你推荐系统电影
趣味:弹球游戏  | 九宫格  | 漂亮的花 | 两百行Python日常酷跑游戏日常酷跑游戏日常酷跑游戏!
AI: 会写诗的机器人会写诗的机器人会写诗的机器人 | 给图片上色给图片上色给图片上色 | 预测收入 | 《耻辱》太火了,我用机器学习做了一部迷你推荐系统电影
小工具: Pdf转Word易于修复表单和水印!易于处理的表单和水印!轻松修复桌子和水印!易于修复的形式和水印! | 一键把html将页面另存为网页另存为网页另存为pdf!|  再见PDF提款费!提款费!提款费!提款费用! | 用90构建最强大的代码行构建最强大的代码行构建最强大的代码行PDF转换器,word、PPT、excel、markdown、html一键转换 | 制作一个固定的低成本机票提醒!制作一张别针的低价机票提醒! |60代码行做了一个语音墙纸切换,天天见女士!

年度弹出文案年度弹出文案年度爆炸性文案

  • 1). 卧槽!Pdf转Word用Python轻松搞定 !

  • 2).学Python闻起来好香!我用100一行代码做了一个网站,帮助人们做了一行代码,做了一个网站,帮助了人们做了一行代码,帮助了人们PS旅行图片赚鸡腿吃旅行图片赚鸡腿

  • 3).第一次播放量过亿,火爆全网,我分析了《波妹》,发现了这些秘密

  • 4). 80一行行代码!使用Python让救济金做正确的事做做的人做好事的人A梦分身

  • 5).你必须掌握的东西你必须掌握20个python代码,简短而紧凑,永无止境的有用代码,简短而甜蜜,永无止境的有用的代码,简短而紧凑,永无止境的使用代码,简短而甜蜜,永无止境的用途

  • 6). 30个Python古怪技能集古怪小贴士收藏古怪技能集

  • 7). 我总结的80《菜鸟学习专页》《菜鸟学习专页》《菜鸟学习》Python精选干货.pdf》,都是干货

  • 8). 再见Python!我要学Go了!2500词深度分析词深度分析词深度分析 !

  • 9).发现了一只舔狗的福利!这Python爬虫神器太酷了,不能自动下载女孩的照片

点击阅读原文点击查看点击点击阅读点击阅读原文点击查看B支持我的视频站我的视频支持我的视频!

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除