生活工程体验信仰哲学精神
投稿投诉
精神世界
探索历史
哲学文学
艺术价值
信仰创造
境界审美
体验技术
技能工具
工程信息
医学生产
生活运用
操作能力

技术分享MySQL如何限制一张表的记录数

11月7日 艮山观投稿
  作者:杨涛涛
  资深数据库专家,专研MySQL十余年。擅长MySQL、PostgreSQL、MongoDB等开源数据库相关的备份恢复、SQL调优、监控运维、高可用架构设计等。目前任职于爱可生,为各大运营商及银行金融企业提供MySQL相关技术支持、MySQL相关课程培训等工作。
  本文来源:原创投稿
  爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
  背景
  本文又是来源于客户咨询的问题:能否控制单表在一个固定的记录数,比如说1W条,超过不让插入新记录或者说直接抛出错误?
  关于这个问题,没有一个简化的答案,比如执行一条命令或者说简单设置一个参数都不能完美解决。接下来我给出一些可选解决方案。
  正文
  对数据库来讲,一般问题的解决方案无非有两种,一种是在应用端;另外一种是在数据库端。
  首先是在数据库端(假设表硬性限制为1W条记录):
  一、触发器解决方案:
  触发器的思路很简单,每次插入新记录前,检查表记录数是否到达限定数量,数量未到,继续插入;数量达到,先插入一条新记录,再删除最老的记录,或者反着来也行。为了避免每次检测表总记录数全表扫,规划另外一张表,用来做当前表的计数器,插入前,只需查计数器表即可。要实现这个需求,需要两个触发器和一张计数器表。
  t1为需要限制记录数的表,t1count为计数器表:mysql:yttnewcreatetablet1(idintautoincrementprimarykey,r1int);
  QueryOK,0rowsaffected(0。06sec)
  mysql:yttnewcreatetablet1count(cntsmallintunsigned);
  QueryOK,0rowsaffected(0。04sec)
  mysql:yttnewinsertt1countsetcnt0;
  QueryOK,1rowaffected(0。11sec)
  得写两个触发器,一个是插入动作触发:DELIMITER
  USEyttnew
  DROPTRIGGER!50032IFEXISTStrt1insert
  CREATE
  !50017DEFINERytt
  TRIGGERtrt1insertAFTERINSERTONt1
  FOREACHROWBEGIN
  UPDATEt1countSETcntcnt1;
  END;
  DELIMITER;
  另外一个是删除动作触发:DELIMITER
  USEyttnew
  DROPTRIGGER!50032IFEXISTStrt1delete
  CREATE
  !50017DEFINERytt
  TRIGGERtrt1deleteAFTERDELETEONt1
  FOREACHROWBEGIN
  UPDATEt1countSETcntcnt1;
  END;
  DELIMITER;
  给表t1造1W条数据,达到上限:mysql:yttnewinsertt1(r1)withrecursivetmp(a,b)as(select1,1unionallselecta1,ceil(rand20)fromtmpwherea10000)
  QueryOK,10000rowsaffected(0。68sec)
  Records:10000Duplicates:0Warnings:0
  计数器表t1count记录为1W。mysql:yttnewselectcntfromt1
  cnt
  10000
  1rowinset(0。00sec)
  插入前需要判断计数器表是否到达限制,如果到了这个限制则删除老旧记录先。我写一个存储过程简单理下逻辑:DELIMITER
  USEyttnew
  DROPPROCEDUREIFEXISTSspinsertt1
  CREATEDEFINERyttPROCEDUREspinsertt1(
  INfr1INT
  )
  BEGIN
  DECLAREvcntINTDEFAULT0;
  SELECTcntINTOvcntFROMt1
  IFvcnt10000THEN
  DELETEFROMt1ORDERBYidASCLIMIT1;
  ENDIF;
  INSERTINTOt1(r1)VALUES(fr1);
  END
  DELIMITER;
  此时,调用存储过程即可实现:mysql:yttnewcallspinsertt1(9999);
  QueryOK,1rowaffected(0。02sec)
  mysql:yttnewselectcount()fromt1;
  count()
  10000
  1rowinset(0。01sec)
  这个存储过程的处理逻辑也可以继续优化为一次批量处理。比如每次多缓存一倍的表记录数,判断逻辑变为在2W条以前,只插入新记录,并不删除老记录,当到达2W条后,一次性删除旧的1W条记录。
  这种方案有以下几个缺陷:
  计数器表的记录更新是由insertdelete触发,如果对表进行truncate则计数器表不触发更新从而数据不一致。
  对表进行drop操作则触发器也跟着删除,需要重建触发器,重置计数器表。
  对表写入只能是类似存储过程这样的单一入口,不能是其他入口。
  二、分区表解决方案
  建立一个range分区,第一个分区有1W条记录,第二个分区为默认分区,等表记录数达到限制后,删除第一个分区,重新调整分区定义即可。
  分区表初始定义:mysql:yttnewcreatetablet1(idintautoincrementprimarykey,r1int)partitionbyrange(id)(partitionp1valueslessthan(10001),partitionpmaxvalueslessthan(maxvalue));
  QueryOK,0rowsaffected(0。45sec)
  查找第一个分区是否已满:mysql:yttnewselectcount()fromt1partition(p1);
  count()
  10000
  1rowinset(0。00sec)
  删除第一个分区,并且重新调整分区表:mysql:yttnewaltertablet1droppartitionp1;
  QueryOK,0rowsaffected(0。06sec)
  Records:0Duplicates:0Warnings:0
  mysql:yttnewaltertablet1reorganizepartitionpmaxinto(partitionp1valueslessthan(20001),partitionpmaxvalueslessthan(maxvalue));
  QueryOK,0rowsaffected(0。60sec)
  Records:0Duplicates:0Warnings:0
  这种方法的优势很明显:
  表插入入口可以很随机,INSERT语句、存储过程、导文件都行。
  删除第一个分区是一个DROP操作,非常快。
  但也有缺点:表记录不能有空隙,如果有空隙,就得改变分区表定义。比如把分区p1的最大值改为20001,那即使在这个分区里有一半的记录不连续,也不影响检索分区里的总记录数。
  三、通用表空间解决方案
  提前计算好这张表1W条记录需要多少磁盘空间,之后在磁盘上划分一个区专门来存放这张表的数据。
  挂载划好的分区,添加为InnoDB表空间的备选目录(tmpmysql)。mysql:yttnewcreatetablespacets1adddatafiletmpmysqlts1。
  QueryOK,0rowsaffected(0。11sec)
  mysql:yttnewaltertablet1tablespacets1;
  QueryOK,0rowsaffected(0。12sec)
  Records:0Duplicates:0Warnings:0
  我大致算了下,不是很准确,所以记录上可能有点误差,不过意思已经很明确:等表报TABLEISFULL后即可。mysql:yttnewinsertt1(r1)values(200);
  ERROR1114(HY000):Thetablet1isfull
  mysql:yttnewselectcount()fromt1;
  count()
  10384
  1rowinset(0。20sec)
  表满后移除表空间,清空表,再插入新记录。mysql:yttnewaltertablet1
  QueryOK,0rowsaffected(0。18sec)
  Records:0Duplicates:0Warnings:0
  mysql:yttnewdroptablespacets1;
  QueryOK,0rowsaffected(0。13sec)
  mysql:yttnewtruncatetablet1;
  QueryOK,0rowsaffected(0。04sec)
  另外一个就是在应用端处理:
  可以提前在应用端缓存表数据,达到限定的记录数后再批量写入数据库端,写入数据库前,先清空表即可。
  举个例子:表t1数据缓存到文件t1。csv,当t1。csv到达1W行时,数据库端清空表数据,导入t1。csv。
  结语
  之前MySQL在MyISAM时代,表属性maxrows来预估表的记录数,但也不是硬性规定,类似我上面写的使用通用表空间来达到限制表记录数的作用;到了InnoDB时代就没有一个直观的方法,更多是靠以上列出来的方法来解决这个问题,具体选哪个方案,还是得看需求。
  文章推荐:
  技术分享TiDB对大事务的简单拆分
  技术分享MySQL内部临时表是怎么存放的
  新特性解读MySQL8。0通用表达式(WITH)深入用法
  社区近期动态
  本文关键字:限制表记录数MySQL通用表空间
投诉 评论 转载

贵州一男子沉迷游戏忘收玉米,怕被责备谎称生病,结果真住进医院导语:一名男子沉迷打游戏忘记收玉米,怕被家人责怪谎称自己生病,结果真的进了医院,让我们一起来看看这究竟是怎么回事吧?近日,在贵州黔西南,一名男子的妈妈临时有事要出门,出门……吃辣火锅时,牛奶和豆浆,谁更解辣?奶粉们,五一期间出行了没?奶叔在家带娃,没机会出去。不过在朋友圈看到好朋友的遭遇,奶叔乐了。好朋友去了重庆,本来信心满满,觉得自己能征服这座魔幻的8D城市,但光是火锅店的……对宝宝进行语言胎教,让宝宝切实感受妈妈的快乐影音胎教:带宝宝看动画片无论自己的胎宝宝是男还是女,孕妈妈都可以按照自己的喜好,带着胎宝宝看看那些经典的动画片,如《猫和老鼠》《狮子王》《白雪公主》《芭比故事系列》《蓝精……我孩子9岁,没有英语基础,适合在鲸鱼小班英语上课吗?求助9岁还没有英语基础,那你确实要上点心了。鲸鱼小班的课程318岁的孩子都可以来学,其实英语最好的启蒙期是5岁左右,像你家孩子应该赶紧追上来。不过也不用太担心,鲸鱼这边对于比较基础……毕业后才知道,读研三年和工作三年的区别,差的可不是一星半点随着人们对于学历的向往,越来越多的本科生选择攻读硕士学位,越来越多的学生开始选择提升自己,一时间,考研的数量急剧增加,考研的竞争一时间变得愈演愈烈。考研的上岸的学生有限,……大学新生开学,家长是否有必要全程陪同,听听过来人怎么说8月已经到来了,好多的大一准大学生马上就要开学了,一到每年的开学季,就会有很多的人出现这样的困扰,到底需不需要家长陪同上学。尤其是对于路途遥远的外省份的学生来说,更是为此……技术分享MySQL如何限制一张表的记录数作者:杨涛涛资深数据库专家,专研MySQL十余年。擅长MySQL、PostgreSQL、MongoDB等开源数据库相关的备份恢复、SQL调优、监控运维、高可用架构设计等。……教育今日早报,2021年10月12日,星期二慧聪希沃教育今日早报,2021年10月12日,星期二,农历九月初七【教育政策】教育部:第二轮双一流建设名单待上级批准后才能公布。教育部、上海市共同成立高校中国……(原创乡土作品15)挑豆粒儿(我们小时候2)挑豆粒儿作者:赵雁明有一项非常普及的儿童成长左脑锻炼方法,被心理学家视为经典绝招,就是弄两个小盆,一双筷子,一个盆里装点小球,然后让孩子拿筷子把球一……独居生活不会做饭?赶紧抛弃外卖选择这款神器吧做菜,是一项非常精细而且麻烦的事情,它不仅仅需要日积月累的技术,还需要天赋。现在的年轻人在脱离家庭在外打工生活的时候,总是会面临做饭这项困难的事情。很多年轻人就会受不了做……开创水稻高产之路湖南省农业科学院党委书记左连生说:袁隆平的世界观突出地表现在他崇高的民族自尊心上。他潜心于杂交水稻的研究,致力于创新。他的科研成果增强了民族凝聚力,弘扬了中华民族的传统美德。……女人是最难防备的毒药阿三觉得自己的身子仿佛在云中飘荡一样,也不知道是怎样进入如心的房间,只觉得眼前的床铺,柜子和那梳妆台好像在转动一样,接着眼前一黑,阿三昏死过去了。等阿三醒来的时候,身上已……
宝宝常吃胡萝卜有什么好处不靠谱的小姨带娃,独得宝宝喜爱,比父母带娃效果好娃哭着闹着不愿去幼儿园?三点原因提前了解,你不慌,孩子也开心房子开关插座布置表我最造句用我最造句大全冻梨为什么用冷水比热水解冻快冻梨用冷水泡多久现在做什么生意赚钱个性主题台历制作年底的赚钱良机公汽里的奇遇秦可卿和贾珍是什么关系秦可卿为什么和贾珍走到一起芹菜怎样催芽国药育儿知识小课堂儿童性教育的六个关键孩子好不好?家长别盲从,客观地评价孩子,会让孩子更有动力五年级写足球赛作文挖鼻孔看似无害,实则暗藏诸多隐患我奇思妙想满分作文400字(精选5篇)比华为Mate50RS保时捷版还贵!iPhone14ProM有关希望期盼的好句苹果手机的外观设计挤牙膏背后的商业秘密新手怎样一步一步练盲打回迁房产权争议的起诉条件是什么笨蛋收高利贷杭州工人误工费应该怎么计算?余秋雨《鸣沙山、月牙泉》原文欣赏夏季清明成长日记

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找