兄弟们。
浅浅的炫个富吧。
说出来你们可能不信。
手机你们有吗?我有。
短信,知道吧?一条一毛钱,我天天发。
你敢想吗?
所以说,年轻人,有钱是真的好。
今天,我们就以短信为话题聊起。
短信,它又叫SMS。
比如说,你有一张短信表(sms),里面放了各种需要发送的短信信息。
sms建表sql sms表
需要注意的是state字段,为0的时候说明这时候短信还未发送。
此时还会有一个异步线程不断的捞起未发送(state=0)的短信数据,执行发短信操作,发送成功之后state字段会被置为1(已发送)。也就是说未发送的数据会不断变少。
异步线程发送短信
假设由于某些原因,你现在需要做一些监控,比如监控的内容是,你的sms数据表里还有没有state=0(未发送)的短信,方便判断一下堆积的未发送短信大概在什么样的一个量级。
为了获取满足某些条件的行数是多少,我们一般会使用count()方法。
这时候为了获取未发送的短信数据,我们很自然就想到了使用下面的sql语句进行查询。
select count(*) from sms where state = 0;
然后再把获得数据作为打点发给监控服务。
当数据表小的时候,这是没问题的,但当数据量大的时候,比如未发送的短信到了百万量级的时候,你就会发现,上面的sql查询时间会变得很长,最后timeout报错,查不出结果了。
为什么?
我们先从count()方法的原理聊起。
count()方法的目的是计算当前sql语句查询得到的非NULL的行数。
我们知道mysql是分为server层和存储引擎层的。
Mysql架构
存储引擎层里可以选择各种引擎进行存储,最常见的是innodb、myisam。具体使用哪个存储引擎,可以通过建表sql里的ENGINE
字段进行指定。比如这篇文章开头的建表sql里用了ENGINE=InnoDB
,那这张表用的就是innodb引擎。
虽然在server层都叫count()方法,但在不同的存储引擎下,它们的实现方式是有区别的。
比如同样是读全表数据select count(*) from sms;
语句。
使用 myisam引擎的数据表里有个记录当前表里有几行数据的字段,直接读这个字段返回就好了,因此速度快得飞起。
而使用innodb引擎的数据表,则会选择体积最小的索引树,然后通过遍历叶子节点的个数挨个加起来,这样也能得到全表数据。
因此回到文章开头的问题里,当数据表行数变大后,单次count就需要扫描大量的数据,因此很可能就会出现超时报错。
那么问题就来了。
myisam和innodb这两个引擎,有几个比较明显的区别,这个是八股文常考了。
其中最大的区别在于myisam不支持事务,而innodb支持事务。
而事务,有四层隔离级别,其中默认隔离级别就是可重复读隔离级别(RR)。
四层隔离级别
innodb引擎通过MVCC实现了可重复隔离级别,事务开启后,多次执行同样的select快照读,要能读到同样的数据。
于是我们看个例子。
为什么innodb不单独记录表行数
对于两个事务A和B,一开始sms表假设就2条数据,那事务A一开始确实是读到2条数据。事务B在这期间插入了1条数据,按道理数据库其实有3条数据了,但由于可重复读的隔离级别,事务A依然还是只能读到2条数据。
因此由于事务隔离级别的存在,不同的事务在同一时间下,看到的表内数据行数是不一致的,因此innodb,没办法,也没必要像myisam那样单纯的加个count字段信息在数据表上。
那如果不可避免要使用count(),有没有办法让它快一点?
count()的括号里,可以放各种奇奇怪怪的东西,想必大家应该看过,比如放个星号*,放个1,放个索引列啥的。
我们来分析下他们的执行流程。
count方法的大原则是server层会从innodb存储引擎里读来一行行数据,并且只累计非null的值。但这个过程,根据count()方法括号内的传参,有略有不同。
server层拿到innodb返回的行数据,不对里面的行数据做任何解析和判断,默认取出的值肯定都不是null,直接行数+1。
server层拿到innodb返回的行数据,每行放个1进去,默认不可能为null,直接行数+1.
由于指明了要count某个字段,innodb在取数据的时候,会把这个字段解析出来返回给server层,所以会比count(1)和count(*)多了个解析字段出来的流程。
理解了原理后我们大概可以知道他们的性能排序是
count(*) ≈ count(1) > count(主键id) > count(普通索引列) > count(未加索引列)
所以说count(*),已经是最快的了。
知道真相的我眼泪掉下来。
那有没有其他更好的办法?
我们回过头来细品下文章开头的需求,我们只是希望知道数据库里还有多少短信是堆积在那没发的,具体是1k还是2k其实都是差不多量级,等到了百万以上,具体数值已经不重要了,我们知道它现在堆积得很离谱,就够了。因此这个场景,其实是允许使用比较粗略的估计的。
那怎么样才能获得粗略的数值呢?
还记得我们平时为了查看sql执行计划用的explain命令不。
其中有个rows,会用来估计接下来执行这条sql需要扫描和检查多少行。它是通过采样的方式计算出来的,虽然会有一定的偏差,但它能反映一定的数量级。
explain里的rows
有些语言的orm里可能没有专门的explain语法,但是肯定有执行raw sql的功能,你可以把explain语句当做raw sql传入,从返回的结果里将rows那一列读出来使用。
一般情况下,explain的sql如果能走索引,那会比不走索引的情况更准 。单个字段的索引会比多个字段组成的复合索引要准。索引区分度越高,rows的值也会越准。
这种情况几乎满足大部分的监控场景。但总有一些场景,它要求必须得到精确的行数,这种情况该怎么办呢?
这种场景就比较头疼了,但也不是不能做。
我们可以单独拉一张新的数据库表,只为保存各种场景下的count。
CREATE TABLE `count_table` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`cnt_what` char(20) NOT NULL DEFAULT '' COMMENT '各种需要计算的指标',
`cnt` tinyint NOT NULL COMMENT 'cnt指标值',
PRIMARY KEY (`id`),
KEY `idx_cnt_what` (`cnt_what`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
count_table表保存各种场景下的count
当需要获取某个场景下的cout值时,可以使用下面的sql进行直接读取,快得飞起。
select cnt from count_table where cnt_what = "未发送的短信数量";
那这些count的结果值从哪来呢?
这里分成两种情况。
如果你对这个cnt计算结果的实时性要求很高,那你需要将更新cnt的sql加入到对应变更行数的事务中。
比如我们有两个事务A和B,分别是增加未发送短信和减少未发送短信。
将更改表行数的操作放入到事务里
这样做的好处是事务内的cnt行数依然符合隔离级别,事务回滚的时候,cnt的值也会跟着回滚。
坏处也比较明显,多个线程对同一个cnt进行写操作,会触发悲观锁,多个线程之间需要互相等待。对于高频写的场景,性能会有折损。
如果实时性要求不高的话,比如可以一天一次,那你可以通过全表扫描后做计算。
举个例子,比如上面的短信表,可以按id排序,每次取出1w条数据,记下这一批里最大的id,然后下次从最大id开始再拿1w条数据出来,不断循环。
对于未发送的短信,就只需要在捞出的那1w条数据里,筛选出state=0的条数。
batch分批获取短信表
当然如果有条件,这种场景最好的方式还是消费binlog将数据导入到hive里,然后在hive里做查询,不少公司也已经有现成的组件可以做这种事情,不用自己写脚本,岂不美哉。
mysql同步hive
count(*) ≈ count(1) > count(主键id) > count(普通索引列) > count(未加索引列)
,但哪怕是性能最好的count(*),由于实现上就需要一行行去算,所以数据量大的时候就是不给力。《丁奇mysql45讲》
兄弟们,最近有点没出息,沉迷在刘亦菲的新剧里,都快忘了写文这件事了。
按照惯例,我应该在这里唯唯诺诺的求大家叫我两声靓仔的。
但今天,我感觉我不配。
所以先这样。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/8-47OvQPWxkTPGUPlWC2SQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。