00:00
大家好,欢迎来到腾讯数据库小课堂啊,今天和大家分享。Bit map的使用方法和介绍。什么是p bit,嗯,这个插件是一个。基于roll bit map而实现的压缩位图存储的一个数据插件,经常会用于什么样子的一些场景,就是大规模数据标签的精准快速查找这样的应用,一个应用场景。既能够节省我们的存储空间,也能够提升我们的查询效率。举个例子,当我们有一张音乐类型的用户标签表,比如说啊,用户ID、用户名以及他所喜欢的音乐类型的标签。这个标签是以数组形式去存储。这种情况。那我们传统的方法可能会就按照我这个表的一个结构啊,去记录一张表,如果说我们需要找到喜欢纯音乐类型的用户,我们就可以根据啊兴趣标签这一列去进行搜索,找到标签当中带有纯音乐的这一个哈。
01:06
然后将数据返回给应用。最简单的做法。就是。按照我们上面的表起来。然后通过。信息标签来就直接进行查询。那么这样做有一个问题就是性能,性能很差。特别数据量大的情况下。几十亿。解释一个用户。当我们标签值又多的情况下,对于我们的数据容量的挑战也会更大。并且我们的性能。不是很好,那么我们的一个做法是什么样子?就是将我们。这个表拆成了三张表。一个用户表,一个标签表,一个是用户标签表,我们将标签ID,因为标签肯定会比用户,比我们的用户少。所以说我们基于标签ID作为组件,用户ID作为一个bit map类型来去存储起来。
02:06
这样既节省了一个。存储的容量又提高了,我们的性能到底能够提高多少的性能,我们等会儿在实战中就可以看到。那么针对这个例子,我们开始实际操作。首先。我们要模拟这么多数据,我们准备了三个函数。第一个函数是创建一个随机字符的函数。第二个函数是随机生成整形数组的一个函数就是数字。辅组的一个函数啊,随机长度啊随机值,第三个是生成一个随机字符数组的一个函数。就模拟我们的一种业务场景。啊,第一种场景就是信息标签的这种场景了。我们。找一个数据库。来进行测试,试一下。
03:11
进到这个数据库当中。我们首先执行创建随机字符的函数的。再去创建,我们生成随机整形的数组。然后。再去执行生成随机字符。数组的一个函数。完成了之后,我们就开始要创建表了。首先,我们。第一种传统做法,创建一张表。把所有的数据全部装到这张表。这张表中。有用户IDUN,有用户名,有T。
04:06
一个字符串数组。然后。在插入。一千万条数据。并且在这个标签里,我们创建一个索引。当然在这个插入过程当中啊,效率会没有那么高,那我们等待执行。那我们执行完成,我们数据插入完了。可以看到我们当前这张表。有U用户名。相应的信息了,那我们怎么去查找。和某个人有共同爱好的哪些其他用户呢?还或者是我们如何查找?具有某个共同爱好的人的数量的用户量。
05:09
首先我们查找带有标签。带有。随便举两个和N个标户列表。可以看到,在加了索引之后,我们通过。这个表查询。Hug就是我们的标签字段。标签字段。当中包含有。GN这个标签和O这个标签的用户。就是通过这条查询出来的。总共语句执行时间是44毫秒。
06:00
那我们想要去查看。这是第一次执行,我们第二次执行,因为数据刚进来,没有命中。第二次执行啊,速度就会性能好很多,因为很多数据已经在内存当中查出来了,就四毫秒就能解决,我再执行也就维持在四毫秒左右。那么我们如何查看?喜欢某两个标签。或者某两种音乐类型就包含两种标签的人有多少个呢?我们可以通过这。Count UN,因为UN是我们的组件。从我们这张表。两个and符号代表。不。就是这个字段当中。或者包含有这个标签,或者包含有这个标签。
07:03
查询。第一次执行是17毫秒执行计划显示。第二次执行是八毫秒。第三次执行也是在八毫秒左右啊,这个就是传统的做法啊,一千万行的数据标签查找。要么是四毫秒。所有的数据输出。统计是八毫秒能够完成。那么第二种做法。方我。因为。可以看到。我们这个表。它的tag字段是直接存储了tag ID信息和tag信息,并没有将tag转变为tag ID。这样我们整个表的存储容量。
08:02
还有查询性能都是一个挑战,那我们第二种优效优化方案就是啊,Tag字段当中的所有tag名直接改成tag ID tag。字典表来去。解决这个问题怎么做呢?首先,我们。创建一个。标签字典表。它有两个字段,一个是标签ID和标签信息。字段类型都是普通的。一个是test。创建完成这张表之后,我们就假设我们有10万个标签。那我们就去插入10万个标签。那等一会儿我们再插,我们再创建另外一张表,这张表用于存储我们的用户和标签信息和和这个表实际上是一致的,只不过信息标签这一列,我们不再存储具体的标签,只而是存储我们的标签ID,所以说我们第一次创建的这张表没办法使用,因为是一个啊。
09:23
就是说创建第二张表,用于存储用户信息。创建完成之后,然后开始插入10万条字,10万条标签数据,标签类型的数据。注册10万的数据啊,随机生成几个字符。然后操作完成了之后。那我们开始插入一千万个账号,数据和刚才一样,同样是一千万个用户。等待我们的插入完成之后,然后再去创建相应的索引。好了,我们插入数据完成了,我们看一下。
10:09
是不一样的。好了,操作完成之后可以看到。我们的tag字段里面存储的就不再是具体的tag值,而是我们的TID。那么还有另外一张表叫。10万条。同样,我们只看十条就可以了,Tag信息、tag名字和tag ID来对应我们的tag标签。一千万条。啊,10万条,那么此时我们想要去查找指定tag。
11:01
的。那些用户怎么去查呢。可以通过我们的circle。啊,刚才我们是直接已经加了索引了,没有,加索引和加了索引的前后区别是挺大的,比如说你看就说。加了索引之前是1000毫秒,就一秒钟,那么。在。啊,加索引之前是一一秒钟,加索引之后啊,实际上就0.17毫秒,这是我之前测试的一个结果啊,今天我们同时重新为大家测试一下。那么我们查找标签ID是。六幺。我。六八和97350的用户列表直接执行这条。第一次执行就会发现。我们数据在没有命中的情况下都只有0.18毫秒,我们再执行一次。
12:00
效率更得到了一个提升,是0.149毫秒,再执行一下。0.146基本就维持在这个效率当中,说明我们。标签字段优化为标签ID。这个性能提升非常明显的。那我们再查一下。包含或的关系。并且查询一下我们的统计数量。比如说和。一个人有共同爱好的这样的一个查询场景。可以发现我们的啊,这个执行可能会就相对较慢了。他的执行计划也会复杂一些。并且开了行。执行是39毫秒效率。有点差。我们再重新执行一下。效率并没有优化多少,还是36毫米。具体原因我们后续来分析。
13:00
那么第二种方法实际上在这种抗的场景下,它的性能也很差,那怎么办呢?那么引入了我们的第三种方案,刚才也说到了,我们第三种方案是使用我们的map这样子的一个插件的方法。我们怎么做呢?首先第一步啊,先创建一个插件。第二个就是创建标签,用户对应表就是标签。通过标签作为组件,然后再看我们的用户。不再为我们的。数组来去存储。反过来存储。然后再引入一个用户表和。一个标签表的做法。首先我们创建插件。这个插件在云数据库啊,已经天然支持了,大家可以。申请即可使用。首先我们创建插件。
14:00
插件创建完成。然后呢?这个表的字段首先是TID,第二个是用户偏移,第三个我们的用户bit啊,就是我们的用户。数组类型,但是呢,我们存储的字段类型就是rolling bit map不再是一个组。完成了这个表的创建。之后。然后我们根据之前。在。第二次测验当中的标签和用户的那个。标签和用户的对应表。
15:12
标签信息颠倒一下来进行反向存储。直接使用我们这条语句可以了,行插入就好了,当我们插入完成之后,然后。我们通过这一张表来查询一下标签含有一三十和200的这些用户个数是多少?可以直接我们这条。首先我们知道我们基于是基于标签作为组件啊,我们直接去查TID啊,在这个范围之内的那些。那些记录即可,那根据这些记录,然后找到相应的用户数组信息,通过这个函数,这个函数是聚合返回数组的一些基数的一个函数,把这个U的基数聚合返回我们的U列表。
16:07
之后。再通过我们的U。就得到了一个唯一值。通过我们的sum函数,就把聚合结果求出来。这样就是具体的执行方法。我们复制这条语句。执行。可以看到我们第一次执行返回四毫秒。一下。0.24毫秒。再执行0.23毫秒,基本上就能够在这个范围之内就能够得到我们的相应的结果了。那么刚才我们通过这条查出了。啊,标签含有一三十两百的用户个数,那我们想要返回列表怎么办啊,这个就很简单了,就不再是count就可以了。直接复制我们这条。
17:01
重新查询。同样,0.29毫秒正常。0.23毫秒正常。啊,比我们之前我自己测试的效率还要更高一些,之前我是0.3号。那么经过测试。会发现三种不同的方案。性能体验是完全不一样的。那么综合来看,我们三种查询。效率。可以明显的看出我们的roll map的能要强悍很多,那我们看一下我们的数据存储容量的区别到底有多大呢?我们可以看一下我们的索引以及占用空间的大小。执行这条。是查看我们刚才创建的所有的表的大小。执行这条查询我们刚才创建的这些表对应的。
18:01
索引大小,首先第一个方案。就这张表。Tag index。这个索引的总大小就是。这两个。大家就行了。我还有,因为还有一个account的组件大小。组件索引大小三个140MB。就意味着。就有着4.5个G的存储容量的占用。那么第二种方案是account。加上我们的tag X这两个表,现在加起来是。这个是一个G啊,将近这个是一个多G。这个。这个是六兆,然后再加上他们的对应的索引啊,看了一对的索引是。帕INDEX2。呃。啊,看了一。
19:00
DK还有。Hu。字典的组件索引。总的加起来。是。1077啊,一个G一个G。一个G3个G。六燥。相对第一种方案啊,占用空间要小了一些。那么第三个方案。是三张表hug字段。UI。这三张表加三张表加起来600多兆,所以。对应的是600兆、六兆和五兆。实际上,相对来说,我们最终roll map完,数据空间容量上完其他两种方案。节省的就不止一点半表,可以通过我们这个表能够很明显的看出来。
20:01
数据容量,我们占用一个G。对比方案一和方案二结束几乎啊是几倍的一个提升。查询共同具备某一个标签的用户个数。第一种方案是八毫秒,第二种方案是20多毫秒,大家也看到了,第三种方案啊,是一毫秒,我们最后一次执行,甚至比一毫秒的效率还更高,是0.23毫秒。那么我们查询包含指定标签的用户列表这种方案,第一种方案是四毫秒啊,在命中之后啊,四毫秒,第二种方案是0.15毫秒啊,这个性能性能的确比较不错。第三种。是map啊,0.3毫秒,相对第二种方案来说要多了一些,但实际上我们这个地方只测试了一千万数据,如果说数据到达了。1亿条、10亿条甚至几十亿条之后,Roll bit这套方案它的性能会愈发的突出,那么第二套方案这个性能就会愈发的跟不上我们roll bit map的这个能力了,大家有条件可以自己去测试一下。所以说rolling bit map在针对于标签。
21:16
范围圈人或者是查找的这种情况,精准查找的这种情况是非常具有优势的。我们的测试文档也会随我们的视频下。简介中列出来,大家可以通过我们的链接测试方案。把我们的搜狗语句复制过去,自行更改,测试一下,看一下ZB的map能力到底怎么样,今天的视频就分享到这里,谢谢大家。
我来说两句