粉丝262获赞2530

买色购中所隐有哪几种类型?在买色购中,所隐有四种类型,分别为主见所隐、普通所隐、唯一所隐和全文所隐。其中前三种我们用的比较多,一般来说每张表都会有主见,那么主见所隐一定会存在 普通锁影和唯一锁影一般是用来优化是否的传音速度,全文锁影基本上不会使用,有其他的替代方案。每日一问,唯一锁影的列可以为闹吗?

那咱们在买菜购物当中呢,默认的存储引擎是 node dp, 那 咱们就聊聊 node dp, 所以 咱们先写个缩写,你看一下,这个大伙肯定都写过嘛,你拿这个例子来说吧啊,前面加个 select 字段,对吧?就是一个等值匹配的例子, 就这儿写吧。 select 这是字段名称嘛?那 from 呢?表明这是产条件 id 零九九, 对吧?咱们执行它 id, 咱们一般都认为它是主键吗?这个主键呢,肯定是非空且非一的,对不对?那这个其实涉及一个问题,啥问题呢?就是咱们还是回到刚才,你去通过 mac 一个音频去操作,然后这个文件的时候,他实际上需要把这个文件加载到 mac 当中去,对吧? 哎,这么一个关系,那你加载的话就有 type o, 那 这块如果说咱把整个文件全加载进来,那是不是有点高?打文字的意思,太亏心了,对吧?用不了那么多。所以说咱们 mac 当中有个有概念叫耶,就是耶, 它支持四八四六三十二,完了呢,你看合适的是多少,它按十六 k 米。还有这么个逻辑, ok, 那 两种情况查找,第一个呢,以主键为搜索条件,就在一个数据页当中进行查找。 这两种情况,第一种情况呢,咱们根据主键来查找 需要的数据,那主键的特点非空且为一嘛,对不对?那就可以在咱们页面当中使用二分查找法,快速定位到对应的槽,然后在遍地槽对应的分组中记录,即可快速查找指定记录。所以这里提到一个算法, 因为主键咱们如果说用默认的都是自增的嘛,这有主键自增,那么在树叶当中就可以通过二分查找嘛,这会有一个算法,二分查找法 或者折半查找,这个效率很高啊,对不对? ok, 那 这会呢,咱们还有个问题,如果这块尾弦它不是,这个不是主键了,那你不是主键的话,这边呢?比如说咱们弄一个 a 值十八的, 那你现在的话艾特的十八很多,他肯定不是主键,对吧?那不是主键的话,他该怎么查找呢?那因为在书页当中并没有对应对非主键,建立所有的页目录,这个页目录跟他一会再说啊,所以我们无法通过二维查找法快速定位像素槽,那这种情况呢,只能从最小记录 就开始找呗,对吧?依次遍历单元当中的每条记录,然后呢对比每条记录中是不是符合这种搜索条件,那也就是呢,可以理解为全面扫描效率是最低的, 低的太低了,对吧?那每条线路呢,在物理磁盘上并不是连续的,而是通过链板的形式连起来的,这样会充分利用磁盘的存储空间,在逻辑上保证连续即可。啊,就这么个东西,那咱们看看这个到底这个锁匙是怎么存的啊? 首先咱们看一个锁尾键,首先知道这个东西两种查询方式,你再换的话,有个主键,还有个非主键,对吧?然后用上面这个这空空,那如果呢,咱们去调电 飞出去,则要进行全表扫描,对吧?那这效率呢?太低了。那这里还提了一个关键概念,这里面用到了一个东西,数据结构叫列表, 这列表都干啥的,一会再说啊。 ok, 那 比如说呢,咱们现在有这么一个缩尾句,我创建一下,对吧?就可瑞创个表黑吧,咱们叫。所以 这边给你个字段,比如说呢, c 一, 我一等类型的 n t c 二呢,也是 n t c 三呢,咱们来个叉类型的,随便写点啊,然后呢,把这个 c 一 搞成主键 and prime key, 完事,这是一个简单的创口语句,对吧?有这么 c 三, c 三三个四段,把 c 一 搞成主键,这也以它为例子啊,咱们看它是怎么去存储这个东西的。 ok, 那 实际上呢,咱们在落盘之后,他的一个基本结构分那么几个部分啊,首先这个值肯定放到词典当中嘛,对吧?就 c 一, c 二, c 三,再 c 一, 就这样,然后 c 二, 再嘚一下 c 三,这是数据库表示表当中的各个的值,自断的值,对吧?这个存到字牌上去,这也没问题。同时呢,这会还有几个,一个叫 ucar type, 记录类型也会放在记录行当中, p i p, 这是咱们所谓的记录类型。还有一个叫 nice record, 这玩意呢,也是一个说明的一个字段, nice 按 c r d, 它表示呢,记录的下条记录。 哎,当然还有个字段啊,不能说字段了,说字段不严谨。它还有一个数据就是其他消息咱得放后边, 其他信息放在这, ok 了,那这块呢,有啥 type? 这块有这么几个值, 一个叫零,跟咱们写 java 代码似的,那 java 是 不是咱们有编程代码,之后有咖啡杯杯,还有宝贝,这是个 java 文件,那这个同样是说明我这一行记录它是什么类型的。哎,这个零,如果这是填零的话,它就表啥呀?咱们普通记录, 那如果是二的话,一呢?先不聊他一是,所以,对吧?咱们写二,二的话呢,表示咱们当前的最小记录, 那有二的肯定来三的对不对?三的话就表示咱们的最大记录的值, 哎,这个字段了解之后,咱们再往外看,这表啥意思呢?下一条?下一条记录的地址相对于本条记录的地址偏量,谁有个地址偏量方便找下条记录。 哎,这有了,那其他信息当中呢?这也包含了隐藏列,这三是数据啊,比如说 c 一 等于一,它等二,它等于字母 c, 对 吧?都可以。那其他信息当中呢,就包含了咱们一些隐藏列的消息,隐藏列的值及呢?记录的额外值, 隐藏的,咱们后期会涉及到,对吧?那如果表当中你没有去主动的添加主键,那就会把这个主键放在隐藏列当中,这么个逻辑。 ok, 这几个了解之后,咱们再来看,把这个显示样式呢更改一下,给它竖起来,哎,就这么来,这咱们记录类型, 这好看一些。 nice 的 值拿下来, c 二的值也拿下来, c 三其他信息, 那它的取值就是零一二三,反正用到零二三,普通记录最好的最大值,这是一个地址的偏移量,那这是咱们数据库存的啥值?其他消息呢?有一个东西叫隐藏列,对吧? ok, 那再画的话咱再来画啊,这是一条记录,对吧?把一些记录呢放在页里,显示的意图是,就这个东西吧,是一条,那你多了之后是变这德行了就,哎,这像啥?你瞅瞅是不是跟表一样了?那把这玩意放在一个数据当中,咱们刚才说了,你数据样大小,十六 kb, 十六 kb, 咱们这么一组织,这样我就放这些东西是不就可以了,对吧? ok。

买手口单表数据量大于两千万行,那性能会明显下降,那这个说法他到底有没有理论依据支撑呢?那今天呢,我们就探究本源,我们来聊聊这件事情。假设我们有这么一张数据表, id 呢,是唯一主见, 而下边这看起来是一行一行的数据呢,我们把它叫做行数据,而 my circle 里边的数据呢,它是放在了 you 着点 i d b 的文件中,那上面 my circle 的表数据在硬盘当中呢,也是类似的,放在了一个 i d b 的文件里面, 虽然在数据表里面,他们看起来像是挨在一起的,但实际上在优者点 i d b 文件中,他们被分成了很多小份的数据页,那每一页的大小呢?是十六 k b, 就像上面这样,我们把视角呢,我们聚焦一下,我们放在了某个页纸上, 那因为行数据呢,被分成了很多份,并且放在了很多个数据页里边,那为了唯一标识他具体是哪一个页,我们需要去引入页号的信息,同时为了把这些数据页给他关联起来,于是就引入了前后指针, 用于指向前后的数据页。那这些字段呢,都被加在了数据页的页头里,那数据页它是需要读写的,那十六 k b 说小也不小,那写到一半页,如果说我们的电源被拔了,那也是有可能发生的,对吧?所以为了保证数据页的一个正确性,还引入了教研机制,这个呢就被加在了页围里面,那剩下的空间呢,才是用来放行数据的。 而如果行数据的行数如果特别多的话,那进入到业内的时候,他需要挨一个便利,那效率呢?实际上也不太行,所以为这些数据呢,生成了一份业目录,那具体实现的细 解呢,不重要,是需要知道它是可以通过二分查找的方式将查询效率呢,从 o n 变成 o log n 就可以了。 那我们再来看一下怎么在这个数据页上查找数据。如果想查一条行数据,我们可以把表空间里的每一页都拉出来,那挨个判断里面的行数据是不是我们要找的, 那如果行数据大了,那信任就慢了,因为每一次查找都有可能要便利所有的行。我们可以在每一个数据页里面选出那 id 最小的行数据,而且只需要他们的主见 id 以及所在页的页号,将他们组成一个新的行数据 放到一个新生成的数据页中。各个新的数据页和之前的页结构并没有什么太大的区别,而且大小呢还是十六 k b。 同时为了跟之前的数据页 进行一个区分,新的数据页里面需要加入页层级的信息,那与数据页之间呢,就有了上下层级的一个概念,就像这样,页和页之间就像是一个倒过来的数,其实这个呢,就是我们常说的 b 加数, 所以最下面的一层其实就是所在的叶子节点,其余的都叫做非叶子节点。当我们想要查找 id 等于二的这条数据,会先查找非叶子节点, 发现向左最小的 id 是一,那向右最小的 id 是四,那 id 等于二的数据如果存在,必定在左边箭头下面, 于是就从词盘里加载左下角的数据页。在数据页里面呢,找到 id 等于二的数据行,那么就完成了查询。上面展示的呢,是两层的数,如果数据变多了,我们还可以通过类似的方法,再往上面再 去构建一层,那么就变成了三层的一个数。另外需要注意的是,上边的数据页的页号,它并不是连续的,他们在磁盘里也不一定是挨在一起的。如果查询过程中两个页都在磁盘中,那么可能最多需要经历两次磁盘 i o 查询, 他们才能被加载到内存之中。接下来重点来了,我们来看一下两千万的这个说法是怎么来的。同样一个十六 k 的液毕加数,最末级节点里放了行数据,而非叶子节点呢,得放用来加速查询的锁引数据,那用来去指向其他十六 k 的数据液,那假设 非叶子节点里面指向其他内存页的指针数量为 x, 那叶子节点能够容纳的行数据为 y, 那乘数呢?我们为 z。 那这棵 b 加数里面能存放的行数据总量 可以通过我上边的公式计算得到。我们先来看一下 x 是怎么算的,我们回去看数据页的结构,被页词节点中,假设掐头去尾,那大概剩下了十五 k 用来存放锁引的数据。每条锁引数据主要有主件和指向页号构成,那主件假设是 big in, 那大小呢?是八个字节,那页号在原码里面呢,大小是四个字节,那么非页词节点里一条数据就是十二个字节左右,用十五 k 除以十二个字节,那么等于幺二八零, 也就是说 x 等于幺二八零。那咱们呢,再来算一下 y 的值,叶子结点和非叶子结点之间的数据结构是一样的,所以也假设掐头去尾,我们给剩下的十五 kb 可以发挥空间,而叶子结点里放的是真正的行数据,那假设一条行数据是一 kb, 一个数据页里面能 放十五行,对吧?那也就是说 y 等于十五,我们回到上面的公式,我们已经知道 x 等于幺二八零,那 y 等于十五。假设 b 加数是两层的,那么就等于二,数据表的总行数呢,那么就是两万。那假设 b 加数的成绩是三层, 那 g 呢,是等于三,那么数据表的总行数呢,就是两千五百万,这个两千五百万呢,就是我们常说单表建议最大行数两千万的一个由来,那毕竟再加一层,那数据呢,就大得有点离谱了, 单层数据页对应的最多三次,那次盘 i o 呢,也比较合理。行数据如果超过一个亿,它一定就慢吗? 上面假设单行数据用了 a k, 所以一个数据页里面能放十五行数据,那如果单行的数据用不了这么多,比如说只有两百五十个字节,那么单行数据他也就能放六十行了,对吧?那同样的 三层 b 加数,那单表它能够支持的行数是不是就乘以四就能达到一个亿,对不对?所以一个亿的数据呢,其实也是三层 b 加数,那在这个 b 加数里面,我们要查找到某一行,那最多也是三次次排 o, 所以说它并不慢,这个呢就很好解释了。 这个呢就是我们今天和大家所聊的内容呢,如果你觉得今天的内容有一些收获的话,那么可以给我一个一键三年,你的支持就是我更新的动力。

好,咱们开始来上课,那么我们上节课呢,了解了我们这个数据数值类型以后,这一课我们再来看一下我们的这个日期和时间类型,日期和时间类型里面我们作为了解就可以了,因为我们很少去用这个 买塞口直接去存储时间啊。那么一般呢,我们用都是用什么?用程序来获得时间戳以后,然后存入到这个买塞口中,那么时间戳由于时间戳啊,在程序里边是整形,对吧?无论是在我们的这个,比如说我们在 pp 里边,那么经常啊,我们会做去运算, 那么这个时候我们存到数据库里的这个值,也一定会把它当做什么整形值来存储,为什么?因为我们要去做运算,那无论我们是通过 pp 来获取的这个时间说,还是通过 java 还是 pass, 那最终我们都是以整形的方式存储到数据库里的, 所以针对数据库里面提供的这个日期和时间类型,我们作为一个了解即可啊。那么在这里面我们先看我底下标的颜色最淡的这些,这一个叫什么? yea 二,对吧?占位一个字节且支持的值是一九零一到二幺五五, 是不是不太可能啊?我们在讲数字类型的时候,我是不是给大家测试了一个字节,就是八个比特,对吧?八个比特支持最大值多少?二百五十五吧, 对不对?哎,所以他这个二幺五五是不是已经超了我们这个范围啊?哎,这个为什么我先给他标成这个颜色,然后先说他呢?因为已经被弃用了 啊,在五点 g 的版本就已经被禁用了啊,那么他实际上是干怎么来做呢?他是给他做了一个拆分啊,比如说零到九十九的这么一个数字, 一个拆分,那么零到六十九比如代表的是吧?代表的是这个一九,比如说这个一九零一到这个这个多少?然后呢?从这个七十到九十九,又表示从多少到二幺五,他是这么样的一个值 啊,所以呢,他不是一个准确的这么一个值,包括在存储的时候,在我们去存储的时候,有可能不同的值显示相同的效果啊,所以他在这里边已经被舍弃了啊。那么往上别的,我们看 dat, dat 它的格式 y y y m m b b 什么意思?你看幺零零零一月一日到九九九九十二月三十一日,这是它能表示的值。那还有 time 呢?是什么?时间,对吧?时间从负的这个到正的这个小时啊?然后再以后 data time 完整格式,对吧? yyy m m l d d h h m m s s, 对吧?干嘛?是不是年月日十分秒啊?哎,你看后面幺零零零一 月一日零点零分零秒到九九九九十二日三十一日二十三点五十九分五十九秒,对吧?还有这个他是什么连起来的?只是什么?没有这个 横杠了,对吧?他是什么意思啊?那这个格式表示什么?表示时间出了从一九七零年一月一日零时零分零秒开始,到二零三七年的某一刻, 看到了吧?实际上他能支持的值应该我没有做过这个测试,但是以前我用别的语言做过测试,支持的值应该是到二零三八年的一月二十七号左右,那个时候他是超过了这个存储的范围,所以不好使了啊。但这个东西呢,我们作为了解就可以了 啊,就足够了。因为我刚才我也说了,我们在存储的时候不会直接去存储这种格式的时间,而是干嘛把时间都转换成时间戳。时间戳是什么意思呢?时间戳就是从一九七零年一月一日零时零分零秒到现在的秒数,就被时间,就被我们称为时间戳。 那么我们用这个时间桌有什么好处呢?大家可以想一下,比如说我想求五分钟以前的时间和五分钟以后的时间,如果我要用这种格式,就很难求出来, 对吧?包括这样的或者是这样的。但是如果我用时间戳的话,他是注意是秒数,我要求五分钟之前呢?那是不是就 五分钟?我把它换成什么?换成秒数是不是三百秒?五分钟之前是不?我减三,当前时间说减三百就是五分钟之前,对吧?如果五分钟之后呢?那是不?当前时间说加三百就是五分钟之后,是不是有利于我们的 运算了?哎,所以对于时间而言,我们一般存的什么存的是时间戳啊,这就是咱们这个买塞扣里边的日期和时间类型,大家作为了解就可以啊。好,本节课我们上到这里。

本视频共计二十分钟,带你一口气吃透 my skill 重点面试题, ctrl 一 ctrl 先 ctrl 念名的区别那我们来看一下这道面试问题啊。呃,我相信有同学,呃经常在公司里面啊,做开发工作啊,呃,你们的 leader 或者说项目经理会说啊,我们要尽量用 ctrl 一, 对吧,不要用 ctrl 星啊。那我可以告诉你啊,这其实是一种误导啊, 我们来看一下为什么这么来说啊。首先待会其实你要知道啊,这三种啊,就统计方式啊,他们呃的结果到底有什么区别啊?那首先大家要知道, count 一 啊,它实质上是统计表中的 行的数量啊,就是它是包含所有行的,不管你知道行中是什么值,比方说是 l 值还是非 l 值,它都会统计。那其实它统计的结果我告诉你啊,跟 count 星是一样的,没有什么太大区别。 count 星也是类似的啊,它也是统计所有行的数量 啊,包括所有列啊,就是呃,就是不管你这个列值啊,它是否围绕值,它都会统计。也就说白了, counter 一 跟 counter 星,它的功能它的结果是类似的 呃,而且我告诉你啊,它们俩的性能其实是差不太多的,特别说,比方说你用 my circle 啊,用的是这种 indo d beta 这种隐形啊,其实,呃, counter 星, 甚至它的性能会比 ctrl 一 还要高,因为 macos 在 底层啊,特别 intel d b 的 存储引擎啊,对抗核芯做了很多优化啊,所以我们更推荐大伙儿如果你用的 macos, 又用的是 intel d b 的 存储引擎,更推荐大伙儿去用 ctrl 七二来统计所有的行数 啊,所以这是很多可能呃,你在公司里面开发,有的同事跟你说啊,尽量用 control 一 一啊,不要用 control 星啊,当然,呃,这种情况你要看数据库啊啊,就是至少在 microsoft intel d b 存储引擎下面啊。 control 十二它的性能可能比 control 一 它的性能更高啊,所以其实你用 control 星 control 一 其实差不了太多啊,所以不要被再被误导啊。 那然后我们再来看一下 control 之段啊,那 control 之段它稍微有一点点区别在哪里?就是呃,它主要是统计我们嗯列里面的非 lo 值的函数, 也就说白了,如果说你现在有十列里面有两列它是绕值,它是不会统计的,也就你通过 ctrl 这一个置断得到结果就是八 ok, 所以 它是呃就 ctrl 置断啊,这是它跟我们 ctrl 一 和 ctrl 新的典型的区别。 ok 啊,这个大伙要知道它们的结果级的区别啊。那其实就我们来看下性能对比,就我们刚说的 ctrl 十二和 ctrl 一 其实差不了太多啊,很多数据库其实对 ctrl 十二它是做过一些优化的,因为它们两个性能差不太多的,其实 我们刚说了,如果是买收口 intel d p 纯正型,推荐你更多的可以去用 ctrl 键啊。那然后我们说的 ctrl 呃至断的话,它性能肯定会慢一些,为什么?因为它需要便利每列数据,它要看你是不是落值,你不是落值,我要把它排除掉, 那所以它的性能肯定是不如 ctrl 二和 ctrl 一 的啊,这是大伙儿要注意的。那以上就是我们说的这几种 ctrl 类型它的区别所在, 买收口的深度分页如何优化?我们来看一下。正面是问题啊啊,首先待会要知道买收口深度分页的一些问题啊,其实说白了就当你的偏移量也 offset 比较大的时候啊,它整个的查询性能会有显著下降,因为说白了买收口底层啊,它会做大量的扫描啊,以及跳过大量的行,它才能够查到你所想要的偏移量, 对吧?那这里面它始终是有大量的磁盘 i o 以及内存消耗,它会严重影响我们的性能啊,那它的一些优化手段啊,主要有这么几种啊,第一种我们可以基于组建或说唯一锁影做优化啊,什么意思?其实就是呃,比方说你在呃上一次查询的时候,你可以把你查询的结果级的最大的那个 id 值把它记录下来, 那我们下一次查询的时候怎么做?我们其实只需要通过先用 id 值跟你上一次查询的结果集的最大的 id 做一次比对,先把一些数据过滤下来,对不对?也就把过往数据过滤下来,然后干嘛再加上你那个分页的限制,那这样的话时常就能减少很很多数据的扫描。 但但但是这种情况大伙要注意啊。呃,它它需要你的数据,也就你的 id 数据,它是连续并且唯一的至真的点, 这种情况才适合。 ok, 其他情况不是特别合适啊。那然后第二种情况就是我们可以通过只查询来做优化,什么意思?就是大伙可以看一下啊,我们可以先比方说我们要查第五十页的数据,对不对?我们可以先通过这么一个只查询, 注意这个只查询我们只查每一行进入的 id, 那 这样的话它扫描的数据量就会小一些,对不对?最终再拿到通过只查询拿到我们表里面,把这十条 id 的 数据给它全部查出来, 那这种方式的话,它其实在性能上面也会比你直接去分页查所有的行的记录,行的所有列数据会稍微高一点 啊,这也是一种优化方式啊。那还有种方式就是我们可以通过覆盖锁影去做优化。什么意思?就是,呃,你在这边去 select 新的时候,你自己去简从业务的角度去思考一下,我是不是需要把这一行的所有记录都查出来?如果不需要,我们尽可能的减少我们查找的那个字段数, 我可能只需要我这一行可能十个字段,我可能只需要查三个字段,那我可以怎么做?那如果这三个字段恰巧都是我们所引字段,那说白了它就是我们说的覆盖,所以嘛,对吧?那你查询的话,你只需要扫描我们的,所以就完事了,它是可以减少我们的回表查整行所有 质段数据的次数的,那他时常在性能上面也是能够得到一定提升的。这我们说的覆盖所有的优化机制上,那还有种其实就我们说的缓存优化机制,但是这种方式可能用到的机会不是特别多,因为他有些前提条件就是需要你 数据变,就是你的数据变动不是很频繁,而且每次查找的结果集要又又达到一定的程度,对不对?如果你缓存命中率很低,没有意义, 对不对?那这是我们说的缓存这种机制啊,他是要看你的业务情况。那还有一种就是我们可以呃,就是根据你的业务情况来做一些优化,比方说呃,有的有的系统啊,他可以提前的,就他的,当然他前提也是你数据量变动不大,这种情况下你可以提前的, 对吧?把一些数据查到我们前端缓存起来,那这样的话,你后续呃,你再去查的时候,你实际上只需要在前端 你的缓存里面去过滤数据就行了,不需要到后端来去查啊,那这也是可以提高我们整个系统性能的。那那当然这种情况你要就我们说说,你要试你的业务允不允许,对吧?而且你的数据变动,你后端的数据的修改啊,变化其实不大的情况下面才能用这种 方式,也就提前我把很多数据啊,我查询好放到前端,然后在前端做涨分页啊,就这种情况也是一种优化的方式。那还有种就是我可以从业务的角度啊,限制你最大查询的页数, 对吧?比方说你一个用户,他一直往后面去分页,一直往后面去翻页,那其实你你思考要从业务角度,你翻的翻了几十上百页之后,后面的数据还有意义吗?其实大多数业务场景下面那些个数据其实没有什么太大意义的,那么其实就可以从业务角度去做一些限制,比方说你可以提示他,比方说翻到了第二十页或者第五十页,第一百页的时候,你可以提示他, 当然这个要根据你的业务情况来定啊,你可以提示他数据太旧,货已过时,请重新查询,或者说你输一些过滤条件给他这样的提示,那这也是可以从业务的角度去优化我们整个系统性的 啊。以上就是我给会列的几种情况啊,分库分表后如何进行跨库卷,我们来看一下。这方面是题啊。呃,其实,呃,说到跨库卷啊,我们大多情况下面都是非常不推荐的,因为大家都知道跨库关联其实性能是非常差的, 对吧?所以其实我们很多时候在做分在分分秒的系统啊,一定要从设计层面就要避免跨库关联查询啊,当然,如果,当然也不是所有情况,对吧?都能够避免的,可能有些情况他就是要跨库关联,怎么办?好,我这里提供几种方案啊 啊?一种我们是可以在应用层面啊,就在你的 java 应用层面啊,做一些关联,也就我们实际上是在多个数呃,分库里面拿到数据,最后再在 java 代码里面做组装,做排序,做结果规定 啊,那这是一种方案,就我们可以在应用层面啊去去做一些结果的整合,那当然啊,第二种方案是我们比较推荐一点的,我们可以做一些数据领域的存储,对吧?比方说,呃,我们有一个订单啊,订单数据库和一个用户数据库,那有的时候我们在查订单的时候啊, 订单里面有一个用户 id, 那 我们可能展示的时候希望把用户名眼展示出来,那这时候如果说你在订单里面只存了一个订单 id, 那 意味着你查询的结果,你要关联一下用户库里面的 数据,拿到用户名,对不对?那这时候如果说你在订单表上面啊,你涌余了,也把用户名涌余进去了啊,哎,那你这时候你就不用再跨库查询了呀,你就查订单库就有结果了,对 不对?那这是我们说数据涌余是比较推荐的一种方案啊。那然后,呃,对于一些中间件啊,它实际上原生就支持我们说的跨库跨表关联查询,比方香菲尔、 my cat, 对 吧?他他们其实也是在多个库里面查到结果,然后再帮你把结果规定整合, 对吧?过滤啊,只不过这些事情他是在中间店层面帮你已经做好了,我们前面说了,应用层面去做,实际上是我们自己去做,对不对啊?如果你用中间店,他会帮你去做,但是我告诉你效率也不会很高啊。 那还有一种方案就是你可以用数据数数据仓库,也就是说白了你可以把很多很多数据啊,都抽取到我们一个大的存储的仓库里面去, 我们对于这种需要跨库跨表关联的查询都走数据仓库,那这样的话他就不存在什么啊,就跨库关联这种问题了。那这也是很多大型的公司啊去做的做的方案之一啊。但是,但是你要知道你加了数据仓库的话,干嘛你就有额外的系统啊,以及运维的运维的成本啊, 对吧?所以这种方案一般是大公司才会去做啊,中小公司一般不会这么干啊。那然后啊,还可以用像缓存啊,对吧?就是,呃,就是对于一些跨库挂表关联的结果啊,如果你能确定这些结果的,呃,关联的数据如果变基本上不不怎么会变动的话,干嘛?你其实可以把结果缓存起来, 对吧?这样的话你下次查询就不用再去跨库跨表关联查询一次,对吧?减少了我们整个系统的查询呃的计算负荷, 对吧?那这也是一种方案,那当然,我说我,我这边也说到了一些风险啊,啊,很注意事项,就我们说性能问题,对吧?我们刚说应用层面啊,你去做跨库跨表关联查询,虽然能实现能得到结果,但是说白了他肯定在性能上面不会很高,对 吧?你想从多个数据库里面查到结果,再统一集中到我们应用层面,应用层面还要做各种规定排序、过滤,那肯定性能不可能高,所以我们一般是说白了不到万不得已不这么来做,一般都要从表里分公分表做设计的时候尽可能 呃的把啊路由键,对吧?或者说分库的一键设计好,避免跨库跨表关联查询,这是最好的方式,那其实我们刚说的对一次性他也是有一些风险的,对吧?比方你做数据总与我们刚说的,你把订单库里面存了一些用户的信息,对吧?那你如果说用户信息变了, 对吧?你是不是还要改一下那个订单库里面相关的信息啊,对吧?那你就要注意维护好数据的一致性,如果你忘记修改,那数据就不一致了, 对吧?那然后还有就我们说的复杂性,就这就我们刚说的,如果说你再搞一个数据仓库,对吧?那这个不是一个小系统啊,对吧?就是他可能需要专门的人去做这件事,可能还有单专门的运维,对吧?这其实带来额外的研发成本啊,这是你需要考虑的。那当然我这边也写了几个最佳实践啊,就是,呃尽量的减少这种跨库的 操作对不对?包括我们的在数据设计的阶段,我刚说了,比方说你做分库分表,你在那个呃分库分表的路由 k, 对 吧?拆分 k 的 设计的时候,你就要尽可能考虑到我们最频繁查询的那种业务场景, 在设计分库分表的时候,就尽可能要规避这种跨步跨表的课程查询。当然这里面我可能今天没办法去举一些实际的案例啊,我之前有专门的那种分库分表的一些实战案例的课程,或者大伙儿如果想要,到时候评论区打个六六六,找找 up 主去领取一下就行了 啊。那当然对于这种情况我们肯定要做一些持续的监控,对吧?比方说如果说跨跨表关联查询很慢的话,我们肯定要监控持续的做优化啊,那这就我们关于分布分表后,我们做跨跨关联查询的一些啊方案以及注意事项。 买蛇口中耐克蘑菇查询如何优化?我们来看一下这个问题啊,就是呃正常情况下面啊,我们很多同学我们可能会用耐克做蘑菇查询,对不对?那比方说像这蛇口语句啊,如果你是这么来写的话,刚好这个 your name 有 缩影的话啊,这是我们比较推荐的一种耐克蘑菇查询啊,它能够很好的利用我们的缩影。 那如果说啊,你现在有个需求啊,你希望把百分号写在前面啊,那这种模糊查询的话,即便你这个 url 这个字段有缩影的话,它也不会用缩影,它会全标扫描,那这种对我们整个的查询性能肯定是有很大影响, 那这种方式有什么优化手段呢啊?我提供几种方式啊?首先,呃,这边这边有一种叫反向缩影的优化方式,什么意思啊?就是,呃,我们可以对你这个字段啊,又比方说我们刚说 url 字段啊,你把它的所有存储的这个制服啊,做一个反向,再存另外一个字段, 比方说你这边是这个时段是转,对不对?那我可以再存另外一个时段,叫 n h o j, 把它反过来再存另外一个时段, ok。 那 我如果说当我要在查正常的这种需求,我要在前面加百分号的时候,那因为他没办法很好的走缩影,对不对?那我可以,那我就可以在另外的那个时段,哎, 用这个时段来去查询,在他的后面加百分号,对不对?那这样的话,这个时段,当然这个时段,这个溶于的这个反向的呃锁影的时段也是需要加锁影,那这种情况的话,他只要是可以走锁影的, ok。 但是这种方式呢,我们也不是说特别推荐啊,因为这种方式的话,你想一下你是不是要多维护一个时段, 对不对?包括这个时段如果说有真删改查操作的话,你这个时段是不是也要对应的做维护?其实没有那么方便啊?那其实我们经常说到的,对于,呃你的百分号,如果,如果说要放在前面的这种模糊查询啊,我们更多的如果你真真的想优化这种情况,我们更多的推荐你可以通过一些搜索引擎 对,比方说像 e s 这样的一些受限型去做,可能会更加方便一点啊,那这也是一种关于模糊查询的优化手段啊。那还有就是我们如果说在做模糊查询的时候,因为模糊查询它可能要匹配很多数据,数量会比较大,对不对?那我们要尽可能的缩小它的一些搜索范围哎,比方说你,你这边做了一个模糊查询对不对?你是不是还可以加一些其他的时段, 把我们的查询的范围尽可能的缩小一点,那这也是能够提高我们性能的。那然后还有一块啊,对于一些呃查询结果啊,如果说它的 呃查询比较频繁,然后它数据的变动又不大的,就它的变动不是很频繁,也就这种情况啊,你其实可以通过缓存来去做的,比方通过 release 把一些经常查询的结果缓存起来,因为它变动数据的变化不是很频繁的话,那其实是可以利用缓存,对吧?只要它命中率 呃,还 ok 的 话,我们其实是可以通过缓存来提高我们整个的查询效率的啊。那以上就是我们经常说到的,像 mac 啊,就是支持耐克模糊查询,你可以做的一些优化手段。 阿里开发者手册啊,为什么禁止超过三张表转啊?那我们来看一下这道面试问题啊,那其实在很多大型的这种供暖公司啊,他的系统病发比较高,数量比较大,一般都是不太建议啊。啊,就是 频繁的使用超多表的关联啊,特别是超过三张表的关联啊,这个是在阿里巴巴的那个开发者手册里面是有明确规定的啊,那这里面的主要涉及到的一些原因,还有就是从可维护性啊,还有就架构设计上面那些 思考啊,那我们来分别来看一下,比方说呃从性能上面思考啊,因为多表关联啊,它就是呃底层是需要有非常复杂的计算的,如果说大伙了解过像表关联之间它底层的执行流程,你就知道啊,它呃表关联,表连接,它底层有大量的哈希连接,包括各种合并连接, 它的整个的计算开销是非常大的,所以其实多表连接它对我们整个的性能开销是有很大影响。那还有一块就是资源的消耗啊,那其实在多表关联的过程中啊,底层啊,它会有大量的内存, cpu 资源的消耗,特别是你的表,如果比较大的话啊,就是比方说有 五六百万,好像甚至千万级别的这种表的话,它底层当你在做关联的时候,它会有大量的内存以及 cpu 资源的消耗啊,我当我们说的是多表,比方超过三张表以上的这种情况,那还有一块就是锁影依赖啊,那对于多表关联啊,如果说呃,你在关联的过程中啊,锁影如果使用不当的话,其实你整个的性查询性能会非常低 啊,就这这条车口就会变成非常慢的查询啊,那这主要是从性能角度去思考啊,那还有一块就是从可扩展性啊,那呃,大伙如果说你有做过那种分库分表的系统的话就知道啊,如果说你做多表关联啊,那很有可能你的这个查询结果的数据啊,会存在多个节点上面, 那意味着你这个关联你做精准操作就会跨多个节点去取数据,那也会导致我们呃大量的数据在多节点之间的数据传输,那会严重的增加我们系统的负担啊。那包括你做数据分片也是一样的,就是你的数据可能落在多个节点分片上面,那整个我们的查询效率是非常低的 啊,那这是从可扩展性的角度去思考,那然后还有一块,就我们说的那个维护以及复杂度啊,那大家知道如果说你的呃 小关联比较多,就一条烧烤鱼就非常长的话,那其实整对后来的开发者,他的维护成本是非常高的啊。那包括如果说你这条烧烤鱼查询的结果有问题,或者说查询性能有问题,你真的要去定位问题以及解决问题,其实也是非常麻烦的。 那这是从我们说的维护以及复杂度的角度去思考,那其实还有就是我们可以从架构的设计的角度去思考一下,比方说你们公司如果做呃领域模型的这种架构的话,那你多你这种多表撞其实也会有影响,对吧?因为呃你的领域模型往往都是单独的一块,那你多表 关联的话,往往会把多个领域模型全部关联在一起,它其实跟我们领域模型设计上是呃背道而驰的,那包括像微幅架构的这种设计思想,也是 呃跟他是相冲突的。比方说我们一个电商系统,那拆了十个微服务,比方说有订单微服务、有库存微服务、有用户微服务等等,有很多,如果说你一条是否有据,你一下查了七八张表,对吧?涉及到五六个微服务,那这其实也是跟我们微服务架构的设计也是相违背的, 那从架构设计上面其实我们也是不建议太多表关联啊。那当然可能有同会问,呃,那,呃如果说我不多表关联啊,我在业务开发过程中啊,可能要呃写很要要要做很多复杂的操作, 对不对?那确实是这样,在一些大厂如果对性能要求非常高的场景啊,那确实是有这种情况发生。但如果说你是一个小公司,系统不是很复杂,数据量也不大,泵也不高,对性能要求也没那么大,多表观点其实也没什么问题啊。这个我们要说一下,我们说的这个问题更多是在一些大厂高泵发海量数据的场景下面, 对吧?我们说像阿里为什么会禁止超过三张表的关联,一般是在那种,对吧?他也不是说阿里内部全部都禁止超过三张表关联,他也是对于那种对性能要求极致,数据量非常大的这种极端的一一些比较核心的系统层面有这些规定,那 当然可能有的问,那我如果不做关联,有没有些什么好的一些替代的一些策略,那我这边也罗列了一些啊。一个是你可以做一些呃反泛式化的设计,比方说你把一些需要关联的数据多存几份,做一些荣誉, 这样的话你就可以减少你的关联需求,那比方说你做数据笼鱼,对吧?你比方你,你在不同表中间,你存一些公共的质段。我举个例子啊,假设我们有一些这种规格啊,或商品规格,或说编码的一些,呃属性 要存储,对吧?那我们往往有一个那个规格编码,可能还有个规格名称,对不对?那特别对这种规格名称的这个质段啊,其实你是可以在多张表里面 做一下荣誉存储的,那这样的话,你在真正查询的时候,你就不不需要说,因为我查一个规格的编码,再去另外一张规格表里面,再把它的名字查出来,你就减少了一张表的关联,那这也是一种数据荣誉的设计,那它其实跟我们,呃,就是数据库的这种范式化的设计啊,实际上是相相冲突的,但是在这种情况下面是可以使用的。 那包括还有就是分而治之,就是我们可以把复杂的查询拆拆为多个简单的查询,查询最终在我们的应用层,也就是比如我们 java 的 web 应用层里面做数据的组合。那有同,就我们刚刚上面说的很多同可能会觉得这种方式,那我 java 里面肯定要写很多的代码。没错,我告诉你,真的如果说在一些高应用开发的要求很高,数量非常大的 这种系统里面,其实我们都这么来干的。这么干虽然你 java 代码可能写的比较复杂,写的比较多,但你要知道 java 程序 web 应用它的扩展 呃容易程度啊,比我们说的数据库会容易很多很多啊。所以这也是我们在婚恋公司我们经常干的一件事啊。那包括还可以采用就是预计算的这种模式。什么意思?就是如果说你有那些,比如说你一些报表查询, 对吧?或者说一些对实时性要求没有那么高的一些场景的话,其实我们是可以把一些结果啊,需要大表关联那些呃呃才能得到的结果,我们可以通过一些预计算的一些任务把它提前算好,当我们查的时候,我们就从之前已经算好的数据结果集里面去拿出去就行, 对吧?这也是一种替代的策略啊。那还有种就是我们说的 no circle 的 数据库啊,那比方说像一些呃文档数据库啊,或者说建值数据库啊,对一些呃你的特定业务场景如果能知识很好的话,那你可以用这种 no circle 的 数据库,它的性能会更高啊。那以上就是我们给大家伙说的一些替代的策略,那如果你面试能把这些点达到,那我们觉得这道问题应该问题不大了啊。