范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

数据库主键一定要自增吗?有哪些场景不建议自增?

  我们平时建表的时候,一般会像下面这样。  CREATE TABLE `user` (   `id` int NOT NULL AUTO_INCREMENT COMMENT "主键",   `name` char(10) NOT NULL DEFAULT "" COMMENT "名字",   PRIMARY KEY (`id`) ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4;
  出于习惯,我们一般会加一列 id作为主键 ,而这个主键一般边上都有个AUTO_INCREMENT  , 意思是这个主键是自增的。自增就是i++,也就是每次都加1。
  但问题来了。
  主键id不自增行不行?
  为什么要用自增id做主键?
  离谱点,没有主键可以吗?
  什么情况下不应该自增?
  被这么一波追问,念头都不通达了?
  这篇文章,我会尝试回答这几个问题。
  主键不自增行不行
  当然是可以的。比如我们可以把建表sql里的 AUTO_INCREMENT  去掉。 CREATE TABLE `user` (   `id` int NOT NULL COMMENT "主键",   `name` char(10) NOT NULL DEFAULT "" COMMENT "名字",   PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  然后执行  INSERT INTO `user` (`name`)  VALUES    ("debug");
  这时候会报错 Field "id" doesn"t have a default value  。也就是说如果你不让主键自增的话,那你在写数据的时候需要自己指定id的值是多少,想要主键id是多少就写多少进去,不写就报错。
  改成下面这样就好了  INSERT INTO `user` (`id`,`name`)  VALUES    (10, "debug");
  为什么要用自增主键
  我们在数据库里保存的数据就跟excel表一样,一行行似的。
  user表
  而在底层,这一行行数据,就是保存在一个个 16k大小的页 里。
  每次都去遍历所有的行性能会不好,于是为了加速搜索,我们可以 根据主键id,从小到大排列这些行数据 ,将这些数据页用双向链表 的形式组织起来,再将这些页里的部分信息提取出来放到一个新的16kb的数据页里,再加入层级的概念 。于是,一个个数据页就被组织起来了,成为了一棵B+树索引 。
  B+树结构
  而当我们在建表sql里声明了 PRIMARY KEY (id)  时,mysql的innodb引擎,就会为主键id生成一个主键索引 ,里面就是通过B+树的形式来维护这套索引。
  到这里,我们有 两个点 是需要关注的: 数据页大小是 固定16k  数据页内,以及数据页之间,数据主键id都是从 小到大排序 的
  由于数据页大小 固定了是16k ,当我们需要插入一条新的数据,数据页会被慢慢放满 ,当超过16k时,这个数据页就有可能会进行分裂 。
  针对B+树 叶子节点 ,如果主键是自增的 ,那它产生的id每次都比前一次要大,所以每次都会将数据加在B+树尾部 ,B+树的叶子节点本质上是双向链表 ,查找它的首部和尾部,时间复杂度O(1) 。而如果此时最末尾的数据页满了,那创建个新的页就好。
  主键id自增的情况
  如果主键不是自增的 ,比方说上次分配了id=7,这次分配了id=3,为了让新加入数据后B+树的叶子节点还能保持有序 ,它就需要往叶子结点的中间找,查找过程的时间复杂度是O(lgn) ,如果这个页正好也满了,这时候就需要进行页分裂 了。并且页分裂操作本身是需要加悲观锁 的。总体看下来,自增的主键遇到页分裂的可能性更少,因此性能也会更高。
  主键id不自增的情况
  没有主键可以吗
  mysql表如果没有主键索引,查个数据都得全表扫描,那既然它这么重要,我今天就不当人了, 不声明主键,可以吗?
  嗯,你完全可以不声明主键。
  你确实可以在建表sql里写成这样。  CREATE TABLE `user` (   `name` char(10) NOT NULL DEFAULT "" COMMENT "名字" ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  看起来确实是没有主键的样子。然而实际上,mysql的innodb引擎内部会帮你生成一个名为 ROW_ID  列,它是个6字节的隐藏列,你平时也看不到它,但实际上,它也是自增的。有了这层兜底机制保证,数据表肯定会有主键和主键索引 。
  跟ROW_ID被隐藏的列还有 trx_id  字段,用于记录当前这一行数据行是被哪个事务 修改的,和一个roll_pointer  字段,这个字段是用来指向当前这个数据行的上一个版本,通过这个字段,可以为这行数据形成一条版本链,从而实现多版本并发控制(MVCC) 。有没有很眼熟,这个在之前写的文章里出现过。
  隐藏的row_id列
  有没有建议主键不自增的场景
  前面提到了主键自增可以带来很多好处,事实上 大部分场景下,我们都建议主键设为自增。
  那有没有不建议主键自增的场景呢?
  mysql分库分表下的id
  聊到分库分表,那我就需要说明下, 递增和自增的区别 了,自增 就是每次都+1,而递增 则是新的id比上一个id要大就行了,具体大多少,没关系。
  之前写过一篇文章提到过,mysql在水平分库分表时,一般有两种方式。
  一种分表方式是通过 对id取模进行分表 ,这种要求递增就好,不要求严格自增,因为取模后数据会被分散到多个分表中,就算id是严格自增的,在分散之后,都只能保证每个分表里id只能是递增的。
  根据id取模分表
  另一种分表方式是 根据id的范围进行分表(分片) ,它会划出一定的范围,比如以2kw为一个分表的大小,那0~2kw就放在这张分表中,2kw~4kw放在另一张分表中,数据不断增加,分表也可以不断增加,非常适合动态扩容 ,但它要求id自增 ,如果id递增 ,数据则会出现大量空洞 。举个例子,比如第一次分配id=2,第二次分配id=2kw,这时候第一张表的范围就被打满了,后面再分配一个id,比如是3kw,就只能存到2kw~4kw(第二张)的分表中。那我在0~2kw这个范围的分表,也就存了两条数据 ,这太浪费了。
  根据id范围分表
  但不管哪种分表方式,一般是 不可能继续用原来表里的自增主键的 ,原因也比较好理解,原来的每个表如果都从0开始自增的话,那好几个表就会出现好几次重复的id,根据id唯一的原则,这显然不合理。
  所以我们在分库分表的场景下,插入的id都是专门的id服务生成的,如果是要严格自增的话,那一般会通过redis来获得,当然不会是一个id请求获取一次,一般会 按批次去获得,比如一次性获得100个。快用完了再去获取下一批100个。
  但这个方案有个问题,它严重依赖redis,如果redis挂了,那整个功能就傻了。
  有没有不依赖于其他第三方组件的方法呢?
  雪花算法
  有,比如 Twitter开源的雪花算法。
  雪花算法通过64位有特殊含义的数字来组成id。
  雪花算法
  首先 第0位 不用。
  接下来的 41位 是时间戳 。精度是毫秒 ,这个大小大概能表示个69年  左右,因为时间戳随着时间流逝肯定是越来越大的,所以这部分决定了生成的id肯定是越来越大的。
  再接下来的 10位 是指产生这些雪花算法的工作机器id ,这样就可以让每个机器产生的id都具有相应的标识。
  再接下来的 12位 ,序列号 ,就是指这个工作机器里生成的递增数字。
  可以看出,只要处于同一毫秒内,所有的雪花算法id的前42位的值都是一样的,因此在这一毫秒内,能产生的id数量就是  2的10次方 2的12次方  ,大概400w  ,肯定是够用了,甚至有点多了。
  但是!
  细心的兄弟们肯定也发现了,雪花算法它算出的数字动不动就比上次的数字多个几百几万的,也就是它生成的id是 趋势递增 的,并不是严格+1自增 的,也就是说它并不太适合于根据范围来分表的场景。这是个非常疼的问题。
  还有个 小问题 是,那10位工作机器id,我每次扩容一个工作机器,这个机器怎么知道自己的id是多少呢?是不是得从某个地方读过来。
  那有没有一种生成id生成方案,既能让分库分表能做到很好的支持动态扩容,又能像雪花算法那样并不依赖redis这样的第三方服务。
  有。这就是这篇文章的重点了。
  适合分库分表的uuid算法
  我们可以参考雪花算法的实现,设计成下面这样。注意下面的每一位, 都是十进制 ,而不是二进制。
  适合分库分表的uuid算法
  开头的 12位 依然是时间,但并不是时间戳,雪花算法的时间戳精确到毫秒,我们用不上这么细,我们改为yyMMddHHmmss  ,注意开头的yy是两位,也就是这个方案能保证到2099年之前,id都不会重复,能用到重复,那也是真·百年企业。同样由于最前面是时间,随着时间流逝,也能保证id趋势递增。
  接下来的 10位 ,用十进制 的方式表示工作机器的ip,就可以把12位的ip转为10位的数字,它可以保证全局唯一,只要服务起来了,也就知道自己的ip是多少了,不需要像雪花算法那样从别的地方去读取worker id了,又是一个小细节。
  在接下来的 6位 ,就用于生成序列号,它能支持每秒钟生成100w个id。
  最后的 4位 ,也是这个id算法最妙的部分。它前2位 代表分库id,后2位 代表分表id。也就是支持一共100*100=1w  张分表。
  举个例子,假设我只用了1个分库,当我一开始只有3张分表的情况下,那我可以通过配置,要求生成的uuid最后面的2位,取值只能是[0,1,2],分别对应三个表。这样我生成出来的id,就能非常均匀的落到三个分表中,这还 顺带解决了单个分表热点写入的问题。
  如果随着业务不断发展,需要新加入两张新的表(3和4),同时第0张表有点满了,不希望再被写了,那就将配置改为[1,2,3,4],这样生成的id就不会再插入到对应的0表中。同时还可以加入生成id的 概率和权重 来调整哪个分表落更多数据。
  有了这个新的uuid方案,我们 既可以保证生成的数据趋势递增,同时也能非常方便扩展分表 。非常nice。
  数据库有那么多种,mysql只是其中一种,那其他数据库也是要求主键自增吗?
  tidb的主键id不建议自增
  tidb是一款分布式数据库,作为mysql分库分表场景下的替代产品,可以更好的对数据进行分片。
  它通过引入 Range 的概念进行数据表分片,比如第一个分片表的id在0~2kw,第二个分片表的id在2kw~4kw。这其实就是根据id范围进行数据库分表 。
  它的语法几乎跟mysql一致,用起来大部分时候是无感的。
  但跟mysql有一点很不一样的就是,mysql建议id自增,但 tidb却建议使用随机的uuid 。原因是如果id自增的话,根据范围分片的规则,一段时间内生成的id几乎都会落到同一个分片上,比如下图,从3kw  开始的自增uuid,几乎都落到range 1  这个分片中,而其他表却几乎不会有写入,性能没有被利用起来。出现一表有难,多表围观 的场面,这种情况又叫写热点 问题。
  写热点问题
  所以为了充分的利用多个分表的写入能力,tidb建议我们写入时使用 随机id ,这样数据就能被均匀分散到多个分片中。
  用户id不建议用自增id
  前面提到的不建议使用自增id的场景,都是技术原因导致的,而下面介绍的这个,单纯是因为业务。
  举个例子吧。
  如果你能知道一个产品每个月,新增的用户数有多少,这个对你来说会是有用的信息吗?
  对程序员来说,可能这个信息价值不大。
  但如果你是做投资的呢,或者是分析竞争对手呢?
  那反过来。
  如果你发现你的竞争对手,总能非常清晰的知道你的产品每个月新进的注册用户是多少人,你会不会心里毛毛的?
  如果真出现了这问题,先不要想是不是有内鬼,先检查下你的用户表主键是不是自增的。
  如果用户id是自增的,那别人只要每个月都注册一个新用户,然后抓包得到这个用户的user_id,然后跟上个月的值减一下,就知道这个月新进多少用户了。
  同样的场景有很多,有时候你去小店吃饭,发票上就写了你是今天的第几单,那大概就能估计今天店家做了多少单。你是店家,你心里也不舒服吧。
  再比如说一些小app的商品订单id,如果也做成自增的,那就很容易可以知道这个月成了多少单。
  类似的事情有很多,这些场景都建议使用趋势递增的uuid作为主键。
  当然, 主键保持自增,但是不暴露给前端,那也行,那前面的话,你当我没说过 。
  总结建表sql里主键边上的 AUTO_INCREMENT  ,可以让主键自增,去掉它是可以的,但这就需要你在insert的时候自己设置主键的值。 建表sql里的  PRIMARY KEY   是用来声明主键的,如果去掉,那也能建表成功,但mysql内部会给你偷偷建一个 ROW_ID  的隐藏列作为主键。 由于mysql使用 B+树索引,叶子节点是从小到大排序的 ,如果使用自增id做主键,这样每次数据都加在B+树的最后,比起每次加在B+树中间的方式,加在最后可以有效减少页分裂的问题。  在分库分表的场景下,我们可以通过redis等第三方组件来获得严格自增的主键id。如果不想依赖redis,可以参考雪花算法进行 魔改 ,既能保证数据趋势递增,也能很好的满足分库分表的动态扩容。  并不是所有数据库都建议使用自增id作为主键,比如 tidb就推荐使用随机id ,这样可以有效避免写热点 的问题。而对于一些敏感数据,比如用户id,订单id等,如果使用自增id作为主键的话,外部通过抓包,很容易可以知道新进用户量,成单量这些信息,所以需要谨慎考虑 是否继续使用自增主键。

视频图片水印太烦人,怎么去掉,又有何用?大家好!朋友们是不是经常看到朋友圈发布的一些精彩视频,美丽的风景图片,甚至于漂亮的小姐姐。是不是好奇为啥同样的视频或者图片别人发出来就没有什么奇怪的水印,而你发出去就有,看着都影响北部湾银行某分行与某支行各被罚未按规定报送资料等来源中国经济网国家外汇管理局广西壮族自治区分局近日公布的行政处罚决定书(柳汇罚20223号崇左汇检罚20221号)显示,广西北部湾银行股份有限公司柳州分行广西北部湾银行股份有限公司自治区供销社与光大银行南宁分行开展座谈交流11月29日,自治区供销社与光大银行南宁分行开展座谈交流。自治区供销社党组书记理事会主任吴浩岭,党组成员理事会副主任陆远万光大银行南宁分行党委书记行长甘欣等出席座谈会并讲话。自治区产能过剩的动力电池,怎么就成了车企涨价的借口?距离新能源汽车购置补贴取消还有不足一月,一场提前透支明年销量的涨价大战早已拉开帷幕。说来也快,新能源汽车购置补贴已10年有余,如今即将成为历史,在多部委发布的关于2022年新能源汽你是吉人,自有天相下班的路上,我乘坐的公交车被堵在靠近医院的路口,我坐在最后一排靠窗的位子,看着窗外,享受一个人的世界。窗外是不绝于耳的汽车鸣笛声,车内有细碎的聊天声,讲电话讲到开心时的笑声,手机公隔离纪事其二9月30日一夜无话,在惶恐与好竒中迎来新的一天。当第一缕暑光透过窗帘的缝隙挤进房间时,时间定格在六点半。我起身打开窗帘,明媚的金光赤裸裸地将我拥抱,带着清新的温热,带着暖心的问候,苹果MR头显明年到!搭载M2芯片体验比iOS更强,售价恐要上万作者FANFAN来源极果编辑部在苹果所有神秘新品里,一款混合现实头戴设备是公开的秘密,从专利图外观,到芯片传感器等,在网上透了个遍。种种迹象表明,这款产品的研发节奏似乎进入了最后冲办公照明智能化规范全屋智能零售店场景化规范正式发布日前,顺舟智能参加的办公照明智能化规范全屋智能零售店场景化规范两大团体标准正式发布。办公照明智能化规范是上海浦东智能照明联合会为推动智能照明的发展,所组织的团体标准。该规范的发布,首次出战省运会收获一金一银吉林小伙金大星愿为儋州继续征战新海南客户端南海网南国都市报12月7日消息(记者梁振文)12月7日,海南省第六届运动会高尔夫球项目落下帷幕。儋州队获得成年组男子团体冠军,海口队李林强张若兮刘恩骅王壹包揽各组别个人北方农村多异姓杂居,南方多同姓聚居,南北宗族观念为何大不同?有一年去海南游玩,打算搞个环岛骑行,从海口出来之后,开始进入乡村,偶然发现这里的村子很多都有祠堂,像什么许氏宗祠,谢氏宗祠,冯氏宗祠等等,祠堂都修得古色古香,非常好看,对于我这个从小米印度高层再地震首席商务官离职,新品发布或遭遇挑战北京时间12月7日,小米印度公司宣布首席商务官拉古雷迪将离职,后者曾帮助小米公司登顶印度智能手机和智能电视市场,拉古雷迪也是继今年六月小米公司印度业务主管马努贾恩退任(转为全球角色
四数据未进前5!周鹏总结三原因!广东第二阶段9胜6负,该醒醒了CBA第二阶段的比赛已经完全结束,各支球队进入本赛季第二个休赛期,球员们也得到了一段相对充足的休息时间。对于广东宏远而言,他们第二阶段的整体表现并不好,在最后一场对阵上海男篮的收尾内讧爆发!联盟第一惨遭双杀,双核无法共存,球队老大已找到下家NBA常规赛继续进行,西部第三的灰熊对阵西部第四的爵士,灰熊本赛季表现让人眼前一亮,尤其是刚刚入选全明星首发的莫兰特展现出了超级球星的潜力,而爵士这边近期受到伤病侵袭。最终,三节拉CBA第二阶段收官,争冠球队已露峥嵘?CBA的这个赛季,可谓命运多舛,一路打打停停,分成了三个阶段。好在前两个阶段已经完成,三分之二的比赛已经打完,常规赛只剩下10场比赛,然后就是惨烈的季后赛我认为,今年有望争霸的还是回归后的汤普森有了什么变化?自从克莱在1月9日回归后,所有的目光都集中在他的身上。这不仅仅是因为他是勇士队中备受喜爱的成员,还因为他是球队中极其重要的一员。他复出那天被称为克莱日,尽管追梦格林在那场比赛之前受回顾男篮那些值得铭记一生的精彩瞬间作为一个铁杆中国男篮球迷,亲眼见证和目睹过很多令人记忆深刻和刻骨铭心的精彩瞬间,今天我们就来回顾一下男篮那些值得铭记一生的精彩镜头!08奥运揭幕战,姚明接刘伟传球三分手起刀落,首开娱乐净土王宝强让马蓉狼狈不堪,第三者判刑,最艰难时不忘报恩前言黄渤拍完泰囧以后受访,提到王宝强时说了一句实话。那是我们普通人根本看不到的一面,和我们认为的王宝强大相径庭。这次拍戏我才知道,王宝强根本不是我们认识中的傻根,那么纯洁善良那么简重磅!詹姆斯无限期休战北京时间1月29日,湖人惜败黄蜂。比这更糟糕的是,美媒爆料詹姆斯的膝盖里面有一些积液,因此这是导致他酸痛的主要原因,这会导致他无限期休战,何时能够参加比赛将会取决于他的恢复情况。万过年手机选哪部?广东人喜爱的几款耐用机,性能颜值样样全不少人回家过年都带了不少年货回家,不少人也计划着在新年给自己换部新手机。从实际体验和使用寿命来看,高端旗舰毫无疑问是首选机型,不少精打细算的广东人买手机也是看中耐用,性价比高,一下我的当下及遐想当下我悄悄的在网上写作写下我自己的人生遭遇写下我自己的人生磨难也写下我自己的人生过往任凭命运多舛任凭岁月的洗礼当下我悄悄的在网上写作写出自己的想法写出自己的梦想写出自己的真情实感也科技指南好物推荐黑莓Q30华为P50Pro与奇怪的boeibei水杯新年将至,帮你找点喜庆的物品来看看,简单的快乐黑莓KEY2PassportQ30曾经认为最最最拉风的机型你还认识吗?如今好像是一块板砖一样。黑莓KEY2PassportQ30配上这哎,这一天生的全是男娃!产科医生的无心之语,让宝妈们倍感忧虑执笔旖旎编辑小文审稿韩韩全文共1350字,阅读时间约3分钟(版权归本作者所有,欢迎个人转发分享)引言最近一则专家鼓励75到85后多生育的话题,引起很多人的关注。查看一下近些年的生育