消息队列

消息队列

消息队列是分布式应用间交换信息的重要组件,消息队列可驻留在内存或磁盘上, 队列可以存储消息直到它们被应用程序读走。

现在比较常见的消息队列产品主要有ActiveMQRabbitMQZeroMQKafkaRocketMQ等。

RabbitMQ

RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是AMQP(高级消息队列协议)的标准实现。

用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

消息队列的使用过程,如下:

  1. 客户端连接到消息队列服务器,打开一个channel。
  2. 客户端声明一个exchange,并设置相关属性。
  3. 客户端声明一个queue,并设置相关属性。
  4. 客户端使用routing key,在exchange和queue之间建立好绑定关系。
  5. 客户端投递消息到exchange。

exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

Kafka

Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。

  • 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。(文件追加的方式写入数据,过期的数据定期删除)
  • 高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万的消息
  • 支持通过Kafka服务器和消费机集群来分区消息
  • 支持Hadoop并行数据加载

消息队列中点对点模型与发布/订阅模式

img

生产者发送一条消息到queue,只有一个消费者能收到。

img

发布者发送到topic的消息,只有订阅了topic的订阅者才会收到消息。

MySQL

SQL语句在MySQL是如何执行的

img

大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。

  • Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
  • 而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。

也就是说,你执行 create table 建表的时候,如果不指定引擎类型,默认使用的就是 InnoDB。不过,你也可以通过指定存储引擎的类型来选择别的引擎,比如在 create table 语句中使用 engine=memory, 来指定使用内存引擎创建表。

查询缓存

由于表经常更新,查询缓存的失效频繁,查询缓存往往利大于弊。,MySQL 8.0 版本开始直接将查询缓存的整块功能删掉了。

优化器

经过了分析器,MySQL 就知道你要做什么了。在开始执行之前,还要先经过优化器的处理。

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的 join:

mysql> select * from t1 join t2 using(ID)  where t1.c=10 and t2.d=20;
  • 既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联到表 t2,再判断 t2 里面 d 的值是否等于 20。
  • 也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到 t1,再判断 t1 里面 c 的值是否等于 10。
    这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。

如果你还有一些疑问,比如优化器是怎么选择索引的,有没有可能选择错等等,没关系,我会在后面的文章中单独展开说明优化器的内容。

执行器

开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返回没有权限的错误,如下所示:

mysql> select * from T where ID=10;

ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T

如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口

比如我们这个例子中的表 T 中,ID 字段没有索引,那么执行器的执行流程是这样的:

  1. 调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;
  2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
  3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

至此,这个语句就执行完成了.

参考:一条SQL语句,在MySQL中是如何执行的

常见存储引擎

存储引擎是数据库的核心,在MySQL中,存储引擎是以插件的形式运行的。支持的引擎有十几种之多,但我们实战常用到的,大概只有InnoDB、MyISAM 和 Memory 了。

InnoDB

InnoDB 从 MySQL5.5(2010年) 版本代替 MyISAM 成为默认引擎。相比MyISAM强调性能,InnoDB 侧重于提供事务支持以及外部键等高级数据库功能。具体特点:

  • 支持事务。默认的事务隔离级别为可重复读(REPEATABLE-READ),通过MVCC(并发版本控制)来实现。
  • 使用的锁粒度默认为行级锁,可以支持更高的并发;当然,也支持表锁。
  • 支持外键约束;外键约束其实降低了表的查询速度,但是增加了表之间的耦合度。
  • 可以通过自动增长列,方法是auto_increment。
  • 配合一些热备工具可以支持在线热备份;
  • 在InnoDB中存在着缓冲管理,通过缓冲池,将索引和数据全部缓存起来,加快查询的速度;
  • 对于InnoDB类型的表,其数据的物理组织形式是聚簇表。所有的数据按照主键来组织。数据和索引放在一块,都位于B+数的叶子节点上。
  • DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

InnoDB的存储表和索引有下面两种形式:

  • 共享表空间存储:所有的表和索引存放在同一个表空间中。
  • 多表空间存储:表结构放在.frm文件,数据和索引放在.ibd文件中。分区表的话,每个分区对应单独的.ibd文件,分区表的定义可以查看我的其他文章。使用分区表的好处在于提升查询效率。

对于InnoDB来说,最大的优势在于支持事务,当然这是以牺牲效率为代价的。

MyISAM

还有好多同学在面试回答 InnoDB 和 MyISAM 区别的时候,依然会带上 InnoDB 不支持全文检索,MyISAM 支持对 BLOB 和 TEXT 的前500个字符索引云云,那是5、6年之前的答案啦。

  • 不支持事务。不支持事务,像是挣脱了枷锁,在读写(Insert、select)效率上,要高于InnoDB不少。场景在:日志记录、调查统计表时,绝对值得一用。对了,不支持事务,自然就不支持锁。

  • 体积小,质量大。MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。同时能加载更多索引,而Innodb的索引和数据是紧密捆绑的,没有使用压缩从而会造成 Innodb 比 MyISAM 数据文件体积庞大很多。

    ​ 每张MyISAM表在磁盘上会对应三个文件。

    ​ (1).frm文件:存储表的定义数据

    ​ (2).MYD文件:存放表具体记录的数据

    ​ (3).MYI文件:存储索引

  • 常常应用部门需要我给他们定期某些表的数据,MyISAM的话很方便,只要发给他们对应那表的(frm.MYD,MYI)的文件,让他们自己在对应版本的数据库启动就行,而Innodb就需要导出.sql了,因为光给别人文件,受字典数据文件的影响,对方是无法使用的。

  • MyISAM表的select count(*) 是非常快的;在 MyISAM 存储引擎中,把表的总行数(row)存储在磁盘上,当执行 select count(*) from t 时,直接返回总数据。同样,当 count(*) 语句包含 where条件时,两种表的操作是一样的。

  • DELETE FROM table时,MyISAM会先将表结构备份到一张虚拟表中,然后执行drop,最后根据备份重建该表。

Memory

可以将它理解为,临时表。Memory是将数据直接存在内存中的,特别适合数据量小的表。同时为了提高数据的访问速度,每一个表实际上和一个磁盘文件关联,文件是frm。

  • 支持的数据类型有限制,比如:不支持TEXT和BLOB类型。对于字符串类型的数据,只支持固定长度的行,VARCHAR(64)会被自动存储为CHAR(64)类型;
  • 只支持表级锁。所以,在访问量比较大时,表级锁会成为MEMORY存储引擎的瓶颈;
  • 由于数据是存放在内存中,一旦服务器宕机,数据就会丢失;数据库主从切换的配置要设置好。
  • 查询的时候,如果有用到临时表,而且临时表中有BLOB,TEXT类型的字段,那么这个临时表就会转化为MyISAM类型的表,性能会急剧降低;
  • 默认使用hash索引。

MySQL 索引为什么采用B+树

MySQL中存储索引用到的数据结构是B+树,B+树的查询时间跟树的高度有关,是log(n),如果用hash存储,那么查询时间是O(1)。既然hash比B+树更快,为什么mysql用B+树来存储索引呢?

  1. 从内存角度上说,数据库中的索引一般时在磁盘上,数据量大的情况可能无法一次性装入内存,B+树的设计可以允许数据分批加载。
  2. 从业务场景上说,如果只选择一个数据那确实是hash更快,但是数据库中经常会选中多条这时候由于B+树索引有序,并且又有链表相连,它的查询效率比hash就快很多了。

为什么不用红黑树或者二叉排序树?

树的查询时间跟树的高度有关,B+树是一棵多路搜索树可以降低树的高度,提高查找效率.

既然增加树的路数可以降低树的高度,那么无限增加树的路数是不是可以有最优的查找效率?

这样会形成一个有序数组,文件系统和数据库的索引都是存在硬盘上的,并且如果数据量大的话,不一定能一次性加载到内存中。有序数组没法一次性加载进内存,这时候B+树的多路存储威力就出来了,可以每次加载B+树的一个结点,然后一步步往下找.

在内存中,红黑树比B树更优,但是涉及到磁盘操作B树就更优了,那么你能讲讲B+树吗?

B+树是在B树的基础上进行改造,它的数据都在叶子结点,同时叶子结点之间还加了指针形成链表。

下面是一个4路B+树,它的数据都在叶子结点,并且有链表相连。

为什么B+树要这样设计?

这个跟它的使用场景有关,B+树在数据库的索引中用得比较多,数据库中select数据,不一定只选一条,很多时候会选中多条,比如按照id进行排序后选100条。如果是多条的话,B树需要做局部的中序遍历,可能要跨层访问。而B+树由于所有数据都在叶子结点不用跨层,同时由于有链表结构,只需要找到首尾,通过链表就能把所有数据取出来了。

参考:为什么mysql索引要使用B+树,而不是B树,红黑树(B树与B+树细节)

内连接、外连接、全连接

内连接表示两个表的交集

外连接左外右外

MySQL没有全连接,只能用左连接 union 右连接的方式来达到等价全连接

事务

数据库事务 :数据库中一组原子性的SQL操作,彼此状态一致。具有ACID特性。

事务是并发控制的基本单位

事务 ACID 特性:

原子性数据库事务是一个整体,其中的SQL操作要么全部提交成功commit要么全部失败回滚rollback,不可分割

一致性:与原子性有联系。事务总是从一个一致状态转换到另一个一致状态

隔离性事务之间彼此互不影响,一个事务在提交之前,对其他事务是不可见的。

持久性一个事务一旦提交成功,他所做的修改就会永久性的存储在数据库中

  • 恢复的实现技术:建立冗余数据 -> 利用冗余数据实施数据库恢复。

  • 建立冗余数据常用技术:数据转储(动态海量转储、动态增量转储、静态海量转储、静态增量转储)、登记日志文件。

MySQL 4 种隔离级别

未提交读 **READ UNCOMMITTED:一个事务在提交之前,对其他事务是可见的,即事务可以读取未提交的数据。**存在“脏读”(读到了脏数据)问题;

提交读 READ COMMITTED:事务在提交之前,对其它事务是不可见的。存在“不可重复读”(两次查询的得到的结果可能不同,即可能在查询的间隙,有事务提交了修改)问题。解决了“脏读”问题。

*可重复读 *REPEATABLE READ:在同一事务中多次读取的数据是一致的。解决了脏读和不可重复读问题,存在“幻读”(在事务两次查询间隙,有其他事务又插入或删除了新的记录)。— MySQL默认隔离级别。

可串行化 SERIALIZABLE:强制事务串行化执行。即一个事物一个事物挨个来执行,可以解决上述所有问题。

锁及粒度

共享锁/读锁:互不阻塞,优先级低

排他锁/写锁:阻塞其他锁,优先级高,即确保在一个事务写入时不受其他事务的影响。

锁粒度锁定的数据量越少(粒度越小), 并发程度越高,但相应的加锁、检测锁、释放锁用的系统开销也随之增大。

锁策略:锁开销与数据安全性之间的平衡

表锁:锁住整张表,读锁互不阻塞,写锁阻塞其他所有读写锁(同一张表)。开销最小。

行级锁:对每一行数据(记录)加锁,开销大,并发程度高。

InnoDB对死锁的处理

与OS死锁类似,多个事务互相持有对方所有要申请资源的锁不释放,造成环路死锁。InnoDB引擎检测到死锁循环依赖后,回滚持有最少行级锁的事务

索引

其作用和实现方法:

概念:对数据库表列进行增加恰当索引,可以快速的找到匹配的记录行数,相比于默认的全表扫描,可以大大加快查找的速度。

作用:加快查找速度

实现方法:一般分为B+树索引和哈希索引。

B+树索引

在B-tree上改进得到,其非叶子节点均为key值叶子节点是key-data键值对。叶子节点前后相连且有序。

哈希索引

通过对key进行hash(crc/MD5/sha1/sha256...)而将记录存储在不同的bucket种,可以做到常数时间的查找,但要注意哈希冲突的避免(链表法、线性探测、二次探测、公共溢出区的方法)。其中MD5 128位,和sha1/256码都较长不太适合作为hash函数。默认无序

为什么有了B+树索引还要hash索引?

B+树默认有序,hash默认无序,所以哈希索引无法用于排序

哈希索引O(1)在速度上毋庸置疑要快于B+树近似O(logn);

哈希索引只能进行等值查询(因为他要计算hash(key)再去匹配)而B+树索引可以进行等值、部分前缀、范围查询;

底层实现结构不同:B+树是 非线性 结构hash桶是 线性 结构

对于某些场景如热点页/活跃查询页,需要借助哈希索引来实现快速查询。

索引越多越快?

此言差矣,索引并非是虚无缥缈的,是实实在在的一种数据结构(B+树/hash桶)要占内存、维护它要系统开销,一般的插入删除都要进行结构的调整,这要消耗时间,所以索引太多反而拖慢查找时间。有时候,见数据量不多时,建立索引还不如全表查询。索引加快了检索的速度,但是插入删除修改都需要DBMS 动态更新内部索引结构 ,要耗费开销

InnoDB MVCC

多版本并发控制,是为了避免加锁而实现的。一般的实现方法是存储快照来实现的。InnoDB实现方式是在记录后添加两个隐藏列(表项),分别是事务创建时间、过期时间,存储的实际上是系统版本号(系统版本号随着事务的创建而递增)。

INSERT 时加上开始版本号,UPDATE/DELETE时加上过期版本号,这样一来在SELECT时,就只访问开始系统版本号 小于 当前的事务的版本号、过期时间要么 未定义 要么在当前版本号 之后 的记录,这样就可以保证:访问的记录是在本事务开始前就存在而且在本事务期间没有过期(被删除或被修改过的)。可以避免脏读、不可重复读、幻读的问题。(个人觉得)

MySQL存储引擎简介

  • InnoDB,最为通用/推荐的一种引擎,支持事务、行级锁、甚至间隙锁(避免幻读)、支持热备份,MVCC,在并发上占优势,系统资源占用多。

  • MyISAM,默认的存储引擎,不支持事务和行级锁,只支持表锁,某些场景性能很好:占用存储上优,查询速度上完胜(大概是InnoDB的3倍)系统资源占用少。

  1. InnoDB支持事务, MyISAM不支持;
  2. InnoDB支持行级锁、表锁;MyISAM只支持表锁;
  3. InnoDB支持MVCC,MyISAM不支持;
  4. InnoDB不支持全文索引,MyISAM支持;
  5. InnoDB支持外键,MyISAM不支持外键;
  6. InnoDB和MyISAM都支持B+树索引,InnoDB还支持自适应哈希索引
  7. MyISAM实现了前缀压缩技术,占用存储空间更小(但会影响查找),InnoDB是原始数据存储,占用存储更大。

PS:大部分情况下,InnoDB都是正确的选择。—《高性能MySQL》

SQL优化

  • 在经常性的检索列上,建立必要索引,以加快搜索速率,避免全表扫描(索引覆盖扫描);

  • 多次查询同样的数据,可以考虑缓存该组数据;

  • 审视select * form tables, 你需要所有列数据吗?

  • 切分查询(大查询切分成为小查询,避免一次性锁住大量数据)

  • 分解关联查询(单表查询,结果在应用程序中进行关联,可以减少处理过程中的锁争用)

  • 尽量先做单表查询

profile 的作用和用法

用于保存SQL语句执行状态,需要手动开启,才可以查看。

MySQL查询的步骤

  1. 客户端发送查询到服务器;
  2. 服务器检查查询缓存query cache(大小写敏感的哈希查找,常数时间)。如果命中,返回缓存中的结果,否则下一步;
  3. 解析语句,生成执行计划;(SQL解析,预处理,优化器生成执行计划);
  4. 根据执行计划,根据存储引擎的不同调用API,执行查询(一棵指令树);
  5. 结果返回客户端

请问MySQL的端口号是多少,如何修改这个端口号

查看端口号

使用命令show global variables like 'port';查看端口号 ,mysql的默认端口是3306

(补充:sqlserver默认端口号为:1433;oracle默认端口号为:1521;DB2默认端口号为:5000;PostgreSQL默认端口号为:5432)

修改端口号

修改端口号:编辑/etc/my.cnf文件,早期版本有可能是my.conf文件名,增加端口参数,并且设定端口,注意该端口未被使用,保存退出。

Redis

Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的映射。

键的类型只能为字符串,值支持五种数据类型:字符串(Sting)、列表(List)、集合(Set)、散列表(Hash)、有序集合(ZSet)。

为什么Redis这么快?

首先,采用了多路复用io阻塞机制
然后,数据结构简单,操作节省时间
最后,运行在内存中,自然速度快

Redis 优缺点

优点

  • 读写性能好,读的速度可达110000次/s,写的速度可达81000次/s。
  • 支持数据持久化,有AOF和RDB两中持久化方式
  • 数据结构丰富,支持String、List、Set、Hash等结构
  • 支持事务,Redis所有的操作都是原子性的,并且还支持几个操作合并后的原子性执行,原子性指操作要么成功执行,要么失败不执行,不会执行一部分。
  • 支持主从复制,主机可以自动将数据同步到从机,进行读写分离。

缺点

  • 因为Redis是将数据存到内存中的,所以会受到内存大小的限制,不能用作海量数据的读写
  • Redis不具备自动容错和恢复功能,主机或从机宕机会导致前端部分读写请求失败,需要重启机器或者手动切换前端的IP才能切换

Redis为什么常常用做缓存?相比于guava有什么优势?

缓存的定义是访问速度比一般随机存取存储器快的一种高速存储器,而因为Redis是基于内存提供了高性能的数据存取功能,其比较显著的优势就是非常的快。

缓存可以分为本地缓存或者分布式缓存,比较常用的guava缓存就是一种本地缓存,其主要特点是轻量并且快速,生命周期随着JVM的销毁而结束,缺点是在多实例的情况下,每个实例都要自己保存一份缓存,这样会导致缓存的一致性出现问题。

Redis则是分布式缓存,在多实例情况下,每个实例都共享一份缓存数据,缓存具备一致性。缺点是要保持Redis的高可用整体架构会比较复杂。

Redis是单线程还是多线程?Redis为什么这么快?

Redis6.0之前是单线程的,为什么Redis6.0之前采用单线程而不采用多线程呢?

简单来说,就是Redis官方认为没必要,单线程的Redis的瓶颈通常在CPU的IO,而在使用Redis时几乎不存在CPU成为瓶颈的情况。使用Redis主要的瓶颈在内存和网络,并且使用单线程也存在一些优点,比如系统的复杂度较低,可为维护性较高,避免了并发读写所带来的一系列问题。

Redis为什么这么快主要有以下几个原因:

  • 运行在内存中
  • 数据结构简单
  • 使用多路IO复用技术
  • 单线程实现,单线程避免了线程切换、锁等造成的性能开销。

Redis6.0之后为什么引入了多线程?

前面也说了Redis的瓶颈在内存和网络,Redis6.0引入多线程主要是为了解决网路IO读写这个瓶颈,执行命令还是单线程执行的,所以也不存在线程安全问题。

Redis6.0默认是否开启了多线程呢?

默认是没有开启的,如需开启,需要修改配置文件redis.conf:io-threads-do-reads no,no改为yes

参考:Redis高频面试题

Redis数据结构

Redis的常见的数据类型有String、Hash、Set、List、ZSet。还有三种不那么常见的数据类型:Bitmap、HyperLogLog、Geospatial

数据类型 可以存储的值 操作
STRING 字符串、整数或者浮点数 对整个字符串或者字符串的其中一部分执行操作
对整数和浮点数执行自增或者自减操作
LIST 列表 从两端压入或者弹出元素
对单个或者多个元素进行修剪,
只保留一个范围内的元素
SET 无序集合 添加、获取、移除单个元素
检查一个元素是否存在于集合中
计算交集、并集、差集
从集合里面随机获取元素
HASH 包含键值对的无序散列表 添加、获取、移除单个键值对
获取所有键值对
检查某个键是否存在
ZSET 有序集合 添加、获取、删除元素
根据分值范围或者成员来获取元素
计算一个键的排名

Redis都可以干什么事

  • 缓存,毫无疑问这是Redis当今最为人熟知的使用场景。再提升服务器性能方面非常有效;
  • 排行榜,如果使用传统的关系型数据库来做这个事儿,非常的麻烦,而利用Redis的SortSet数据结构能够非常方便搞定;
  • 计算器/限速器,利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力;
  • 好友关系,利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好友、共同爱好之类的功能;
  • 简单消息队列,除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制,比如:到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦;
  • Session共享,以PHP为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论用户落在那台机器上都能够获取到对应的Session信息。

Redis不能干什么事

用Redis去保存用户的基本信息,虽然它能够支持持久化,但是它的持久化方案并不能保证数据绝对的落地,并且还可能带来Redis性能下降,因为持久化太过频繁会增大Redis服务的压力。

简单总结就是数据量太大、数据访问频率非常低的业务都不适合使用Redis,数据太大会增加成本,访问频率太低,保存在内存中纯属浪费资源。

img

img

img

参考:为什么要用Redis

MonGoDB

是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案,是非关系数据库当中功能最丰富,最像关系数据库的

组成

数据库

一个mongodb中可以建立多个数据库。MongoDB的默认数据库为”db”,该数据库存储在data目录中。
MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

命令

show dbs 显示所有数据库

​ 可以显示所有数据库的列表

db 显示当前数据库

​ db显示当前数据库

use 指定某个数据库

​ use命令可以连接到一个指定的数据库

show collections 显示数据库中的所有集合

​ 显示当前数据库中所有的集合

集合(类似Mysql中的表)

文档(类似Mysql中的行,一条数据)

文档是一组K-V键值对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点

1. 特点

字段可以自定义,不一定要类型都一样

  1. 文档中的键/值对是有序的
  2. 值的类型多样:文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型
  3. MongoDB区分类型和大小写。
  4. MongoDB的文档不能有重复的键。
  5. 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

字段(类似Mysql中的列)

主键(_id)

主键 (MongoDB 提供了 key 为 _id )

注意:Mongdb的主键是多了一个下划线的!

MongDB优缺点

优点

1. 存放数据格式是JSON,支持层级存放

支持层级存放,能够更方便的获取数据

如果使用关系型数据库的话,可能需要多张表来完成

2. 内置GridFS,支持大容量的存储(查询块)

GridFS是一个出色的分布式文件系统,可以支持海量的数据存储。内置了GridFS了MongoDB,能够满足对大数据集的快速范围查询

3. 内置Sharding

TODO

4. 查询性能好

查询性能、操作数据的性能都比关系型数据库要好

2. 缺点

1. 不支持事务(4.0版本后支持事务了)
2. 占用空间过大

相关CRUD语法

参考链接:MongoDB常用语法及基本使用

以集合user为例

1. 指定集合 db.

语法为:db.getCollection(‘user’)

2. 插入数据 db..insert(doc)

例如 db.getCollection(‘user’).insert({…}) ;

insert里面填写user的json信息

tips:如果插入时没有给文档指定_id属性,则数据库会自动为文档添加_id属性(ObjectId)

3. 删除数据 db..remove({},Boolean)

db.getCollection(‘user’).remove({“userId”:“1”});

remove里面填写条件,格式为(字段名:字段值

4. 修改数据 db..update({查询条件},{新对象},{options})

例如 db.getCollection(‘user’).update({“userId”:“013”}, {$set:{“email”:“b13@sina.com”, “age”:20}});

使用$set

增加修改文档中的指定属性

使用$unset

用来删除文档中的指定属性

update里面填写条件;set里面

5. 查询数据 db..find({条件})

find中填写json格式的条件

Mongodb与Redis应用指标对比

MongoDB和Redis都是NoSQL,采用结构型数据存储。二者在使用场景中,存在一定的区别,这也主要由于
二者在内存映射的处理过程,持久化的处理方法不同。MongoDB建议集群部署,更多的考虑到集群方案,Redis
更偏重于进程顺序写入,虽然支持集群,也仅限于主-从模式。

指标 MongoDB(v2.4.9) Redis(v2.4.17) 比较说明
实现语言 C++ C/C++ -
协议 BSON、自定义二进制 类Telnet -
性能 依赖内存,TPS较高 依赖内存,TPS非常高 Redis优于MongoDB
可操作性 丰富的数据表达、索引;最类似于关系数据库,支持丰富的查询语言 数据丰富,较少的IO MongoDB优于Redis
内存及存储 适合大数据量存储,依赖系统虚拟内存管理,采用镜像文件存储;内存占有率比较高,官方建议独立部署在64位系统(32位有最大2.5G文件限制,64位没有改限制) Redis2.0后增加虚拟内存特性,突破物理内存限制;数据可以设置时效性,类似于memcache 不同的应用角度看,各有优势
可用性 支持master-slave,replicaset(内部采用paxos选举算法,自动故障恢复),auto sharding机制,对客户端屏蔽了故障转移和切分机制 依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制;不支持自动sharding,需要依赖程序设定一致hash机制 MongoDB优于Redis;单点问题上,MongoDB应用简单,相对用户透明,Redis比较复杂,需要客户端主动解决。(MongoDB 一般会使用replica sets和sharding功能结合,replica sets侧重高可用性及高可靠性,而sharding侧重于性能、易扩展)
可靠性 从1.8版本后,采用binlog方式(MySQL同样采用该方式)支持持久化,增加可靠性 依赖快照进行持久化;AOF增强可靠性;增强可靠性的同时,影响访问性能 MongoDB优于Redis
一致性 不支持事务,靠客户端自身保证 支持事务,比较弱,仅能保证事务中的操作按顺序执行 Redis优于MongoDB
数据分析 内置数据分析功能(mapreduce) 不支持 MongoDB优于Redis
应用场景 海量数据的访问效率提升 较小数据量的性能及运算 MongoDB优于Redis


实习      C++ 面经

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!