redis和mysql区别

redis和mysql区别,第1张

1、类型不同

MySQL是关系型数据库;而Redis是非关系型数据库。

2、作用不同

mysql用于持久化的存储数据到硬盘,功能强大,但是速度较慢。

redis用于存储使用较为频繁的数据到缓存中,读取速度快。

3、存储类型不同

redis存储的是key-value格式的数据。时间复杂度是O(1),常数阶,而MySQL引擎的底层实现是B+Tree,时间复杂度是O(logn),对数阶。Redis会比MySQL快一点点。

mysql数据存储是存储在表中,查找数据时要先对表进行全局扫描或者根据索引查找,这涉及到磁盘的查找,磁盘查找如果是按条点查找可能会快点,但是顺序查找就比较慢;而Redis不用这么麻烦,本身就是存储在内存中,会根据数据在内存的位置直接取出。

只有 MEMORY 存储引擎的表才可以选择使用 BTREE 索引或者 HASH 索引,像我们 常用的innodb只支持btree索引 。两种不同类型的索引各有其不同的适用范围。

Hash索引只能用于对等比较,例如=,<=>(相当于=) *** 作符。时间复杂度是O(1),一次查找便能定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以Hash在 单值查询 下检索效率远高于BTree索引。

但是,事实上我们更多情况是使用btree而不是hash

HASH 索引有一些重要的特征需要在使用的时候特别注意,如下所示。

下面我们可以进行验证:

创建一个city_memory表,其中 country_id字段上加了 HASH索引

插入数据

1、先开看这条等值条件sql

2、那么再来看 大于和小于条件sql

3、那么in这种范围条件呢?

in 条件对于hash来说是支持的,同样btree当然也支持。而且btree索引在使用in条件找数据时相对于hash性能更好,因为rows由4变为2(说明使用btree扫描2行即可找到)证明如下:

4、 BETWEEN .. AND .. 条件呢?

BETWEEN .. AND .. 条件在 不会用到hash索引!再来看看 btree的情况:

BETWEEN .. AND .. 条件能够使用到btree索引。

5、like 条件呢?

为了使用like条件,我们先将country_id类型改为 varchar

我们再来执行:

like条件会让hash索引失效。我们再来看btree下的like怎样:

好的,btree下也支持 like的不带开头%的访问查询

1、先来看hash索引支不支持排序

hash索引果然不能用在排序中,这多么致命呀!产生了 Using filesort文件内排序。性能上是个大坑。

2、同样,我们知道分组是要基于排序的。排序不使用索引,分组当然也不使用索引了。验证如下:

最终不仅没使用到索引,还产生了文件内排序和使用临时表。

当使用 MEMORY 引擎表的时候,如果是默认创建的 HASH索引,就要注意 SQL 语句的编写,确保可以使用上索引,如果索引字段需要 范围查询、排序、分组 就请使用btree索引;

页是 InnoDB 管理存储空间的最小单位。一个页的大小一般是 16 KB。InnoDB 有许多种页用于不同的作用。其中数据页则是用于存储数据。数据页存储的内容为:

其中 Infimum + supremum 以及 User Records 为页中存储数据的部分。其中 Infimum 表示页中的最小记录,而 supremum 表示页中的最大记录。这两个记录不存储实际的值,而仅仅表示开头以及结尾。User Records 部分按行存储数据。User Records 中的每一条记录格式为:

插入到页中的记录是按主键大小进行排序。利用其中的 next_record 可以查找到下一条记录。在不考虑索引的情况下,如果我们要寻找其中的某条记录可以通过遍历链表的方式进行查找。但是如果当页中的数据过多,o(n) 的时间复杂度明显不满足快速查找的需求。因此 InnoDB 在页中设计了页目录。页目录中有多个槽,其规则如下:

因此实际搜索时,可以利用槽进行二分搜索,将算法复杂度降到了 。这个结构有点类似于一个两层的跳跃表。

由于一个页中实际能存储的数据有限,因此记录会被分配到多个页进行存储。页与页之间有着双向链表的结构。

在 innodb 中使用 B+ 树作为索引。实际上索引在 mysql 中也是作为页进行管理的。例如:

索引页与数据页类似,只是索引页中一条记录只存在两列。分别是页对应的最我号,以及页的页编号。当然,一个 b+ 树肯定存在多个级别,因此实际上的存存储格式为:

这里可以看出索引页与数据页其实并没有太多的区别。只不过数据页中存储着真实的数据,而索引页只存储索引。这里也可以看出主键索引实际上是聚集索引,当查找到最终的数据页时是可以直接获得数据。

许多个页组成的空间之为页空间。每个表空间对应着一个真实的文件 表名.ibd。每一个独立表空间中又会分为多个区。每一个区实际上是 64 个连续的页组成。每256个区划又会分为一组。

为什么会提出区的概念呢?原因是查找数据的时候,在页与页之间会通过双向链表进行查找。如果两个页随机分配物理地址,则其之间的物理位置可能非常远。那么在查找的时候无疑会形成大量的随机 IO。降低磁盘的性能。因此,当表中数据过大的时候,以区为单位进行分配连续的磁盘空间,可以减少随机 IO 的数量。

表空间中还有段的概念,当我们利用索引进行查询的时候。很多时候实际上是利用 B+ 树的叶子节点进行范围扫描。但是如果将索引页和数据页都存放在一个区中,那么数据页不一定是连续的磁盘空间。因此当进行范围扫描的时候又会存在随机 IO 的情况。因此索引页和数据页实际上是存放在不同的区中。存放索引页的区的集合又成为一个段,当然非索引页存放的区的集合则为另一个段。

我们知道,磁盘的速度是远远小于内存的速度。因此 InnoDB 会将查询的页缓存在内存 Buffer Pool 中,以免每一次请求都从磁盘中获取,加快查询速度。当然,内存不可能无止尽的使用。因此 InnoDB维护了一个 free 链表。 free 链表指向 Buffer Pool 中可用的部分。

当页面进行修改之后,缓存的中的页页不会马上落盘,这样的页称为脏页。InnoDB 维护了一个 flush 链表指向了脏页。当 buffer 的空间不足时,InnoDB 会进行刷页 *** 作,将脏页写入到磁盘中,腾出内存空间供新的页缓存使用。

一般来说,数据有冷热之分。如果经常刷新热点数据到磁盘中,肯定不划算。因为热点数据经常被查询修改,当写入到磁盘中后又会很快读入到缓存中,做了很多无用功。因此 InnoDB 采用了 LRU 算法统计哪些是热点数据,哪些是非热点数据。每次刷盘时从首先 LRU 链表的尾部将热点数据刷入到磁盘中。

InnoDB 并不是采用最简单的链表,而是划分区域的链表。其设计的原因是,InnoDB 在某些时候会采取预读的 *** 作,将一个区的数据全部读入到内存中。这些数据就会出现在 LRU 链表的头部。如果这些预读的数据最终不能被查询,那么真正的热点数据反而被挤到了链表的尾部,这样一旦存在预读行为 LRU 链表的功能就丧失了。同样,当用户进行扫描全表的 *** 作时,大量的页也会被加载到缓存中将 Buffer 占满。因此 InnoDB 将 LRU 分为两个区域-热数据(young 区)以及冷数据(old 区)。

对于第一种情况,当页被缓存到 Buffer 时首先会被放在 old 区。如果该页后续被继续访问,则会被放到 young 区中。而如果该页后续没有被继续访问到,则会逐渐移动到 old 区尾部。

对于扫描全表的情况,扫描全表有一个特点。即页中的每一条数据都会被访问到,同一个页第一次访问到最后一次访问的间隔时间一定很短。因此 InnoDB 设计了一个策略,如果当一个页加载到内存中,并且该页在第一此访问与最后一次访问间隔相差小于 1s (默认值),则该页就不会被加入到 young 区中。因此这种方式可以避免全表扫描时对 LRU 链表的污染。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/7291117.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-03
下一篇 2023-04-03

发表评论

登录后才能评论

评论列表(0条)

保存