为什么建议主键整型自增?

yizhihongxing


昨天看到一个MySQL数据库设计原则:强烈建议表的主键使用整型自增主键。为啥呢?

要弄明白这个问题首先需要了解MySQL是如何维护数据的,你需要知道以下几点:

  • MySQL的InnoDB存储引擎是在B+树上维护表数据的
  • B+树是一种平衡树
  • 在这棵树上,每个节点在计算机中叫做数据页,默认16k
  • 树的叶子节点是完整的行数据,非叶子节点是主键
  • 叶子节点中的行数据按id从小到大的顺序排列

PS:MySQL索引底层数据结构详细分析过程参考这篇深入分析MySQL索引底层原理

查询过程

明白了MySQL维护数据的方式,下面我们再来看一下如何在这棵树上查询数据。

假设我们有个T表,表结构和数据如下:

CREATE TABLE `T` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(50) COMMENT '姓名',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into T(id,name) 
values(1,'张三'),(2,'李四'),(3,'王五'),(5,'赵六');

了解了MySQL维护数据的方式,我们可以把T表的数据存储逻辑结构画出来:

image

如上图所示,根节点上维护了主键2和5,两个叶子节点分别存两条记录。

当我们查询id=2的记录时,首先会从树的根节点开始遍历,通过与根节点的id值比较,定位到记录在第一个叶子节点,然后把第一个叶子节点从磁盘加载到内存,在内存中依次读取记录进行比较:

  • 读取第一个记录,发现id不等于2跳过
  • 继续取下一个记录,判断id等于2
  • 于是就查到了id等于2的这条记录

可以发现,查找过程是从根节点开始的,通过与非叶子节点的id比较,定位到数据所在节点,然后依次遍历节点上的记录逐一对比,从而找到匹配条件的记录。

插入过程

再来看一下插入数据,如果此时插入的数据为(6,’孙七’),按照叶子节点的行数据排序特点(按id从小到大排),那么(6,’孙七’)这条记录一定在(5,’赵六’)后面,如果此时数据页P3还能存下,则直接顺序写入,如果数据页P3存不下这条记录,InnoDB会申请一个新的数据页P4写入(6,’孙七’),这个过程叫做页分裂。

如果此时插入的数据为(4,’孙七’),按照叶子节点的行数据排序特点(按id从小到大排),那么(4,’孙七’)这条记录一定在(3,’王五’)后面(5,’赵六’)前面,如果此时数据页P3还能存下,那么为了给(4,’孙七’)腾位置,则需要将数据页P3上(3,’王五’)这条记录之后的数据全部往后移动。而如果数据页P3存不下这条记录,InnoDB会申请一个新的数据页P4,并将P3上部分数据转移到P4上,在(3,’王五’)后写入(6,’孙七’)。

为什么主键建议整型、自增?

了解了数据的存储方式以及查询过程和插入过程,我们接下来进入正题,回答为什么主键建议是整型、自增这个问题。

首先为什么是整型呢?

我们从查找过程可以看到,整个过程关键点就是在这棵树上不停的比较id值是否等于、大于还是小于2,即数据的大小比较。数据比较是消耗CPU的,而不同的数据类型耗时不同,常见的整型要小于字符型。

整型的1<2比较的效率高还是字符串的“abc”和“abe”比较的效率高呢?显然是前者,因为字符串的比较是转换成ASCII码一位一位的比,如果最后一位不一样,比到最后才比较出大小,就比整型比较慢多了,存储空间来说,整型更小。索引越节约资源越好。

那为什么自增呢?

原因也可想而知,其实上面已经提到了,就是因为InnoDB的索引是按大小排好序的,插入的新数据如果主键是自增的,那么只需要按顺序往后写入即可,性能会比较高,而如果每次插入的主键是跳跃式的,那么就会涉及到上面说的页分裂,需要挪动数据,性能就会受到影响。

引申一下,是不是一定需要自增呢?

答案是不。我们都知道当某一个业务量增长非常快,数据量非常大,数据库性能无法满足业务需求的时候通常会实施分库分表,这个时候自增主键就不适用了,比如订单表,分成16个表,如果都使用自增的话,肯定会造成订单id重复,所以此时的解决方案就是分布式id,保证趋势递增即可。

小结

今天我通过讲解MySQL数据的存储方式以及数据查找与插入过程,从MySQL的底层机制了解了MySQL主键为什么建议使用整型并且自增,最后我们引申了一个分布式id的问题,此时并不强制严格自增,保证趋势递增即可。

好了,今天的文章就到这里了,如果你对于今天的文章有疑问,请留言探讨。

感谢你的观看,也欢迎你把这篇文章分享给更多的朋友一起阅读。

原文链接:https://www.cnblogs.com/ibigboy/p/17276288.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:为什么建议主键整型自增? - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • MySQL错误ERROR 1615 解决方法

    当我们使用MySQL进行开发时,有时可能会遇到ERROR 1615的错误。这种错误提示通常是由于我们试图更改具有自动递增值的主键列。以下是解决此类问题的方法: 问题产生的根本原因 该错误通常在我们尝试向具有自动递增值的主键列添加行时发生。可以通过更改表中主键列的值来解决此问题。但是,我们不希望出现这种情况,因为主键应该始终是唯一的。因此,我们需要想出其他方法…

    MySQL 2023年5月18日
    00
  • Navicat连接MySQL提示1045错误解决(重置MySQL密码)

    下面就是“Navicat连接MySQL提示1045错误解决(重置MySQL密码)”的完整攻略。 问题描述 在使用Navicat连接MySQL数据库时,出现了错误提示:“1045 – Access denied for user ‘root’@’localhost’ (using password: YES) ”,这个错误很可能是由于MySQL管理员密码错误或…

    MySQL 2023年5月18日
    00
  • mysql中key 、primary key 、unique key 与index区别

    CREATE TABLE pre_forum_post ( pid int(10) unsigned NOT NULL COMMENT ‘帖子id’, fid mediumint(8) unsigned NOT NULL default ‘0’ COMMENT ‘论坛id’, tid mediumint(8) unsigned NOT NULL defaul…

    MySQL 2023年4月13日
    00
  • MySQL错误代码:1052 Column ‘xxx’ in field list is ambiguous的原因和解决

    问题描述: 在MySQL执行SQL语句时,若字段列表中的某个字段名在多张表中都出现了,系统就无法判断要选哪张表中的该字段,从而引发错误。 错误信息提示: MySQL错误代码: 1052 Column ‘xxx’ in field list is ambiguous 解决方案: 为了解决这个问题,需要采取以下的措施: 使用表别名 在多表查询中可以使用表别名(将…

    MySQL 2023年5月18日
    00
  • MySQL 实例无法启动的问题分析及解决

    那我就为您详细讲解MySQL实例无法启动的问题分析及解决的攻略。 问题背景 MySQL是一个广泛使用的关系型数据库管理系统,但有时我们会遇到MySQL实例无法启动的问题。这里将讲解MySQL实例无法启动的原因,并提供相应的解决方案,以帮助大家尽快解决该问题。 问题分析 当MySQL实例无法启动时,我们需要根据以下几方面来进行问题分析: 1. 检查MySQL配…

    MySQL 2023年5月18日
    00
  • 连接MySQL时出现1449与1045异常解决办法

    接下来我将详细讲解“连接MySQL时出现1449与1045异常解决办法”的完整攻略。 原因分析 在连接MySQL数据库时,可能会出现两种异常,分别是1449和1045异常。这两种异常的原因如下: 1449异常:这是由于MySQL用户没有足够的权限来执行特定的操作(如更新、删除等)而导致的异常。 1045异常:这是由于MySQL用户提供的用户名或密码不正确而导…

    MySQL 2023年5月18日
    00
  • MySQL (一) 生产环境安装配置

    一、简介 MySQL是最流行的开放源码SQL数据库管理系统,它是由MySQL AB公司开发、发布并支持的。有以下特点: MySQL是一种数据库管理系统。 MySQL是一种关联数据库管理系统。 MySQL软件是一种开放源码软件。 MySQL数据库服务器具有快速、可靠和易于使用的特点。 MySQL服务器工作在客户端/服务器模式下,或嵌入式系统中。 有大量可用的共…

    MySQL 2023年4月12日
    00
  • mysql开启主从复制

    主数据库配置:vim /etc/my.cnf server_id=146 #一般设置ip最后一位 log-bin=mysql-bin #开启bin-log binlog_do_db=test #生成test数据库binlog_do_db=sss #生成sss数据库binlog_ignore_db=sss #忽略数据库#查看配置是否生效 show VARIAB…

    MySQL 2023年4月13日
    00
合作推广
合作推广
分享本页
返回顶部