
内容来自网络,非原创
数据库
一、事务
ACID
1、原子性(atomicity)
一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性
2、一致性(consistency)
事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。
如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于一种不正确的状态,也就是不一致的状态
3、隔离性(isolation)
事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。
在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同,分别是:未授权读取,授权读取,可重复读取和串行化
4、持久性(durability)
一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。–即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态
隔离级别
1、读未提交(Read Uncommited)
该隔离级别允许脏读取,其隔离级别最低;比如事务A和事务B同时进行,事务A在整个执行阶段,会将某数据的值从1开始一直加到10,然后进行事务提交,此时,事务B能够看到这个数据项在事务A操作过程中的所有中间值(如1变成2,2变成3等),而对这一系列的中间值的读取就是未授权读取
2、授权读取也称为已提交读(Read Commited)
授权读取只允许获取已经提交的数据。比如事务A和事务B同时进行,事务A进行+1操作,此时,事务B无法看到这个数据项在事务A操作过程中的所有中间值,只能看到最终的10。另外,如果说有一个事务C,和事务A进行非常类似的操作,只是事务C是将数据项从10加到20,此时事务B也同样可以读取到20,即授权读取允许不可重复读取。
3、可重复读(Repeatable Read)
就是保证在事务处理过程中,多次读取同一个数据时,其值都和事务开始时刻是一致的,因此该事务级别禁止不可重复读取和脏读取,但是有可能出现幻影数据。所谓幻影数据,就是指同样的事务操作,在前后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。在上面的例子中,可重复读取隔离级别能够保证事务B在第一次事务操作过程中,始终对数据项读取到1,但是在下一次事务操作中,即使事务B(注意,事务名字虽然相同,但是指的是另一个事务操作)采用同样的查询方式,就可能读取到10或20;
4、串行化
是最严格的事务隔离级别,它要求所有事务被串行执行,即事务只能一个接一个的进行处理,不能并发执行。
不隔离的问题
1.脏读:
脏读是指一个事务在处理数据的过程中,读取到另一个为提交事务的数据。
1 | --原数据 |
事务1并没有提交,name 还是 lisi,但是事务2却读到了 name = wangwu,这就是脏读。如果换成A给B转账,B查询到了没有提交的事务,认为已经收到A转过来的钱,那岂不是很恐怖。
不过在实际开发中,应该很少有人会犯这样的低级错误。
2.不可重复读:
不可重复读是指对于数据库中的某个数据,一个事务范围内的多次查询却返回了不同的结果,这是由于在查询过程中,数据被另外一个事务修改并提交了。
1 | --原数据 |
不可重复读和脏读的区别是,脏读读取到的是一个未提交的数据,而不可重复读读取到的是前一个事务提交的数据。
而不可重复读在一些情况也并不影响数据的正确性,比如需要多次查询的数据也是要以最后一次查询到的数据为主。
3.幻读
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
1 | --原数据 |
不可重复读和幻读是初学者不易分清的概念,我也是看了详细的解读才明白的,总的来说,解决不可重复读的方法是 锁行,解决幻读的方式是锁表。
引擎
InnoDB: 支持事务和行级锁,不支持FULLTEXT类型的全文索引,支持外键,增加表之间的耦合度,速度会降低,提供事务支持,
MyISAM: 只支持表级锁,支持 FULLTEXT类型的全文索引,不支持外键,不提供事务支持,所以速度更快。磁盘上会有三个文件:frm文件(表),MYD文件(数据),MYI文件(索引)
1、MyISAM是非事务安全的,而InnoDB是事务安全的
2、MyISAM锁的粒度是表级的,而InnoDB支持行级锁
3、MyISAM支持全文类型索引,而InnoDB不支持全文索引
4、MyISAM相对简单,效率上要优于InnoDB,小型应用可以考虑使用MyISAM
5、MyISAM表保存成文件形式,跨平台使用更加方便
Memory:数据存在内存,出现故障会丢失数据,支持表级锁
锁
悲观锁
总是假设最坏的情况,每次去拿数据(修改)的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。悲观锁的实现,往往依靠数据库提供的锁机制 。
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
乐观锁一般会使用版本号机制或CAS算法实现。
版本号机制
CAS算法
mysql
1.基本命令
登录 :mysql -u root -p123456
1 | show databases; #显示库 |
查看数据库内存状况
1 | select |
查看数据表内存状况,需指定库名
1 | select |
2. 索引
索引分类
从数据结构角度
B+树索引(O(log(n))):关于B+树索引,可以参考 MySQL索引背后的数据结构及算法原理
hash索引:
仅仅能满足”=”,”IN”和”<=>”查询,不能使用范围查询
其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引
只有Memory存储引擎显示支持hash索引
从物理存储角度
聚集索引(clustered index)
存数据
非聚集索引(non-clustered index)
存主键,找到主键再进行搜索
从逻辑角度
普通索引 index :加速查找
唯一索引
主键索引:primary key :加速查找+约束(不为空且唯一)
唯一索引:unique:加速查找+约束 (唯一)联合索引
-primary key(id,name):联合主键索引
-unique(id,name):联合唯一索引
-index(id,name):联合普通索引全文索引 fulltext :用于搜索很长一篇文章的时候,效果最好。
空间索引 spatial :了解就好,几乎不用
索引创建
1.普通索引
是最基本的索引,它没有任何限制。它有以下几种创建方式:
(1)直接创建索引
1 | CREATE INDEX index_name ON table(column(length)) |
(2)修改表结构的方式添加索引
1 | ALTER TABLE table_name ADD INDEX index_name ON (column(length)) |
(3)创建表的时候同时创建索引
1 | CREATE TABLE `table` ( |
(4)删除索引
1 | DROP INDEX index_name ON table |
2.唯一索引
与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:
(1)创建唯一索引
1 | CREATE UNIQUE INDEX indexName ON table(column(length)) |
(2)修改表结构
1 | ALTER TABLE table_name ADD UNIQUE indexName ON (column(length)) |
(3)创建表的时候直接指定
1 | CREATE TABLE `table` ( |
3.主键索引
是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引:
1 | CREATE TABLE `table` ( |
4.组合索引
指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合
1 | ALTER TABLE `table` ADD INDEX name_city_age (name,city,age); |
5.全文索引
主要用来查找文本中的关键字,而不是直接与索引中的值相比较。fulltext索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的where语句的参数匹配。fulltext索引配合match against操作使用,而不是一般的where语句加like。它可以在create table,alter table ,create index使用,不过目前只有char、varchar,text 列上可以创建全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE index创建fulltext索引,要比先为一张表建立fulltext然后再将数据写入的速度快很多。
(1)创建表的适合添加全文索引
1 | CREATE TABLE `table` ( |
(2)修改表结构添加全文索引
1 | ALTER TABLE article ADD FULLTEXT index_content(content) |
(3)直接创建索引
1 | CREATE FULLTEXT INDEX index_content ON article(content) |
数据结构
B树
(1)排序方式:所有节点关键字是按递增次序排列,并遵循左小右大原则;
(2)子节点数:非叶节点的子节点数>1,且<=M ,且M>=2,空树除外(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2则是2叉树,M=3则是3叉);
(3)关键字数:枝节点的关键字数量大于等于ceil(m/2)-1个且小于等于M-1个(注:ceil()是个朝正无穷方向取整的函数 如ceil(1.1)结果为2);
(4)所有叶子节点均在同一层、叶子节点除了包含了关键字和关键字记录的指针外也有指向其子节点的指针只不过其指针地址都为null对应下图最后一层节点的空格子;
(5)非叶节点中的信息包括[n,A0,K1,A1,K2,A2,…,Kn,An],,其中n表示该节点中保存的关键字个数,K为关键字且Ki<Ki+1,A为指向子树根节点的指针。
最后我们用一个图和一个实际的例子来理解B树(这里为了理解方便我就直接用实际字母的大小来排列C>B>A)
B树的查询流程:
如上图我要从上图中找到E字母,查找流程如下
(1)获取根节点的关键字进行比较,当前根节点关键字为M,E<M(26个字母顺序),所以往找到指向左边的子节点(二分法规则,左小右大,左边放小于当前节点值的子节点、右边放大于当前节点值的子节点);
(2)拿到关键字D和G,D<E<G 所以直接找到D和G中间的节点;
(3)拿到E和F,因为E=E 所以直接返回关键字和指针信息(如果树结构里面没有包含所要查找的节点则返回null);
查找、删除过程略
B树的时间复杂度:
树高度:h<=logT*(n+1)/2, 时间复杂度为:O(logn).
B树的特点:
树相对于平衡二叉树的不同是,每个节点包含的关键字增多了,特别是在B树应用到数据库中的时候,数据库充分利用了磁盘块的原理(磁盘数据存储是采用块的形式存储的,每个块的大小为4K,每次IO进行数据读取时,同一个磁盘块的数据可以一次性读取出来)把节点大小限制和充分使用在磁盘快大小范围;把树的节点关键字增多后树的层级比原来的二叉树少了,减少数据查找的次数和复杂度;
B+树
概念
B+树是B树的一个升级版,相对于B树来说B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。为什么说B+树查找的效率要比B树更高、更稳定;我们先看看两者的区别
规则
(1)B+跟B树不同B+树的非叶子节点不保存关键字记录的指针,只进行数据索引,这样使得B+树每个非叶子节点所能保存的关键字大大增加;
(2)B+树叶子节点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到。所以每次数据查询的次数都一样;
(3)B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。
(4)非叶子节点的子节点数=关键字数(来源百度百科)(根据各种资料 这里有两种算法的实现方式,另一种为非叶节点的关键字数=子节点数-1(来源维基百科),虽然他们数据排列结构不一样,但其原理还是一样的Mysql 的B+树是用第一种方式实现);
特点
1、B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
3、B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。
B-树相对于B+树的优点也就是B+树的缺点
但是B树也有优点,其优点在于,由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。
因为B+树比B树的读写代价更低,所以B+树比B树更适合操作系统的文件索引和数据库索引。
3.使用原则
一般来说,应该在这些列上创建索引:
在经常需要搜索的列上,可以加快搜索的速度;
在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
关于最左前缀的说明:
最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
什么时候索引会失效
1. or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效
2. 对于多列索引,不是使用的第一部分,则不会使用索引(即不符合最左前缀原则)
3. like查询是以%开头
4. 数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描。
5. 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
6. 对索引字段进行计算操作、字段上使用函数
7. 在索引字段上使用not,<>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 优化方法: key<>0 改为 key>0 or key<0。
8. 在索引列上使用 IS NULL 或 IS NOT NULL操作。索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可。
技巧和注意事项
- 索引不会包含有null值的列
只要列中包含有null值都将不会被包含在索引中,复合索引中只要有一列含有null值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为null。 - 使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个char(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。 - 索引列排序
查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。 - like语句操作
一般情况下不推荐使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。 - 不要在列上进行运算
这将导致索引失效而进行全表扫描,例如
1 | SELECT * FROM table_name WHERE YEAR(column_name)<2017; |
- 不使用not in和<>操作
- 如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length。
测试索引
4. MySQL 索引优化
explain
EXPLAIN可以帮助开发人员分析SQL问题,explain显示了mysql如何使用索引来处理select语句以及连接表,可以帮助选择更好的索引和写出更优化的查询语句。
使用方法,在select语句前加上Explain就可以了:
1 | Explain select * from blog where false; |
type表示MySQL在表中找到所需行的方式
常用的类型有:ALL、index、range、 ref、eq_ref、const、system、NULL
ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
index: Full Index Scan,index与ALL区别为index类型只遍历索引树
range:只检索给定范围的行,使用一个索引来选择行
ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
5.索引优化情况记录
记录一次索引优化过程以供参考
调试模式中显示原系统中的时间开销主要来源是两个,一是统计这个表的行数,简称计数,二是查询当前页要显示的目标,简称显示。
经过简单的测试,发现加上一个索引后对整个表的影响非常复杂。对于全表的展示,加一个索引可大大加快计数的速度,显示的速度基本不变。而对索引字段加上范围进行筛选后,情况又分为以下两种,当页数靠前,计数速度加快,显示速度变慢,页数靠后,计数速度加快,显示速度大大减慢。
对于加了索引的字段,对该字段进行筛选效果反而不好。但是除此之外的速度均有不同程度的提升。
索引建立后会占用大量存储空间,这部分空间在索引删除后仍然显示占用。
我目前的猜想是由于我采用的查询语句为
1 | SELECT * FROM employees WHERE age > 50; |
在仅有一个索引,也就是主键id的情况下,mysql会直接遍历整个表,对每一行的age字段进行判断,筛选出结果,虽然耗时长一些,但也相对简单。
而在添加了索引index_age之后,mysql更倾向于使用index_age,先在index_age生成的B+树中找到符合age>50的项,由于在InnoDB引擎中index_age是非聚集索引,而查询列中包含了其他该索引没有覆盖的列,因此需要回表查询,获取这一行的主键,再依据主键到原表中找到对应行的信息。而由于age均匀分布在18到70的范围内,age>50的人数大约占总人数的三分之一以上,因此需要回表数百万次,造成了严重的超时问题。
解决办法也很简单,少用SELECT * 这样的搜索语句,把常搜索的字段建立一个联合索引,避免回表即可
我查了网上的资料后觉得回表这个问题完全是存在的,但是在验证这个想法的过程中发现,回表的影响确实存在,但是超时可能不是完全由其造成,有索引的条件下单独运行
1 | select * from `employees` where `age` between '40' and '60' ; |
用时10秒左右,并不是很长,而问题的关键在于下面这条语句,用时达到70秒以上
1 | select * from `employees` where `age` between '40' and '60' limit 20 offset 3959760; |
两条语句explain的情况如下
1 | limit 20 offset 3959760; |
这段是一个where后的额外条件,引出了Extra:Using index condition; Using MRR
其中Using index condition解释如下
Using index condition是MySQL 5.6中引入的一种新特性,叫做Index Condition Pushdown(ICP),是一种在存储引擎层使用索引过滤数据的一种优化方式。这里的“下推” 是指将原来在server层进行的table filter中可以进行index filter的部分,在引擎层面使用index filter进行处理,不再需要回表进行table filter。使用ICP可以减少存储引擎层返回需要被index filter过滤掉的行记录,省去了存储引擎访问基表的次数以及MySQL服务器访问存储引擎的次数。Using index condition仅适用于二级索引,原因是ICP的目的是减少全行读取的次数,从而减少IO操作。而对于innodb聚集索引,完整的记录已被读入到innodb缓冲区,在这种情况下,ICP不会减少io,所以ICP只适用于二级索引,一般发生在查询字段无法被二级索引覆盖的场景,该场景下往往需要回表。通过ICP,可以减少存储引擎返回的行记录,从而减少了IO操作。
至于MRR解释如下:MRR 通过把「随机磁盘读」,转化为「顺序磁盘读」,从而提高了索引查询的性能。
经不那么可靠的测试,MRR对查询影响不大
limit offset语句中offset后过大的数字应该是问题的根源,
在网上找到了解决方案,offset本就是个臭名昭著的语句,经常产生巨量的开销,找到一种解决方案如下,
1 | select * from employees a inner join (select id from employees where `age` between 40 and 60 limit 20 offset 3459760) b on a.id=b.id |
可以将数据表与自身连接,先找出age,再根据id找全部信息,这样相当于原有的300000次回表被减少到15次,在age索引中的查询又非常快,总时间就比较短了。
索引差不多就到这里了
MySQL主从
redis
简介
Redis 是一个高性能的 key-value 数据库。
Redis 是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的key-value类型的数据(String),同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave模式的数据备份。
mysql和redis因为需求的不同,一般都是配合使用。
redis一般会应用在下面一些场景
排行榜、计数器、消息队列推送、好友关注、粉丝
MySQL存储在磁盘里,Redis存储在内存里,Redis既可以用来做持久存储,也可以做缓存,而目前大多数公司的存储都是MySQL + Redis,MySQL作为主存储,Redis作为辅助存储被用作缓存,加快访问读取的速度,提高性能.
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
启动
1 | redis-server.exe redis.windows.conf |
MongoDB
MongoDB是NoSQL文档存储模式数据,它支持的查询语言非常强大
主要功能特性有:
- 面向集合的存储:适合存储对象及JSON形式的数据。
- 高性能、易部署、易使用,存储数据非常方便。
- 动态查询:Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
- 完整的索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。
- 查询监视:Mongo包含一个监视工具用于分析数据库操作的性能。
- 复制及自动故障转移:Mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目标是提供冗余及自动故障转移。
- 高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)
- 自动分片以支持云级别的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器。
MongoDB的优点
- 面向文档:MongoDB是面向文档的,数据在数据库中的存储格式与您要在服务器端脚本和客户端脚本中处理的格式非常接近。
- 高性能:MongoDB是市面上性能最高的数据库之一。
- 高可用性:MongoDB的复制模型使其很容易保持高可用性,同时能够提供高性能和高可扩展性。
- 高可扩展性:应用程序数据集的大小正在飞速地增长
- 对SQL注入攻击免疫:MongoDB将数据存储为对象,而不使用SQL字符串,因此对SQL注入攻击免疫。
适用场合
MongoDB 的适用场景为:数据不是特别重要(例如通知,推送这些),数据表结构变化较为频繁,数据量特别大,数据的并发性特别高,数据结构比较特别(例如地图的位置坐标),这些情况下用 MongoDB , 其他情况就还是用 MySQL ,这样组合使用就可以达到最大的效率。
网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源 过载。
大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。Mongo的路线图中已经包含对MapReduce引擎的内置支持。
用于对象及JSON数据的存储:Mongo的BSON数据格式非常适合文档化格式的存储及查询。
不适用场合
- 高度事务性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
- 传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。
MongoDB的逻辑结构
是一种层次结构,主要由文档(document)、集合(collection)、数据库(database)这三部分组成的
文档(Document)
文档(Document)是MongoDB中数据的基本存储单元(类似于关系数据库中的行,但是比行要复杂得多),是表示单个实体的数据。
多个字段(Field)及其关联的值(Value)有序地放置在一起的字段/值(field: value)对便是文档。
MongoDB的文件存储格式为BSON,是一个JSON文档对象的二进制编码格式。
集合
MongoDB使用集合将数据编组。集合就是一组用途相同或类似的MongoDB文档,类似于传统关系数据库中的表,但存在一个重要差别:在MongoDB中,集合不受严格模式的约束,其中的文档可根据需要采用不同的结构。
操作命令
插入文档
insert()、save()、insertOne()和insertMany()
更新文档
update()、updateOne()、updateMany()、replaceOne()或者save()
删除文档
deleteOne()、deleteMany()、remove()
查询文档
可以用find()方法查询指定集合中满足条件的全部文档,也可以用findOne()查询满足条件的第一个文档
MongoDB的复制
复制的作用:保证数据的安全性,保证数据的高可用性(24*7),用户灾难恢复,不需要停机维护(如备份,重建索引,压缩等任务),读写的灵活性
MongoDB 用副本集实现复制的功能。副本集是一组托管同一数据集的 mongod 对象。在副本集中有三个成员:主节点(Primary)、从节点(Secondary)、仲裁节点(Arbiter)
副本集具有 2 个或多个节点(但一般最少需要 3 个节点)。
副本集只有一个主节点,其他全是从节点,只有主节点才对外提供读写服务。
所有数据都是从主节点复制到从节点上的。
仲裁节点有复杂的优先级、自动调权机制,确保选举结果的顺利完成。当发生自动故障转移或维护时,会重新推举一个新的主节点。
当失败节点恢复后,该节点重新又连接到副本集中,重新作为从节点。
MongoDB的分片
分片是指将数据拆分,将其分散在不同机器上的过程。
MongoDB的分片是指定一个分片key来进行,数据按范围分成不同的chunk。
通过分片能够增加更多的机器,来应对不断增加的负载和数据。
MongoDB何时分片:
机器的磁盘不够用
单个mongod已经不能满足写数据的性能需求
想将大量的数据放在内存中提高性能
一般来说,集群先从不分片开始,然后在需要时才转换成分片。
什么要使用复制呢?如果我们的数据库只存在于一台服务器,若这台服务器宕机了,
ElasticSearch
Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析和探索的能力。充分利用Elasticsearch的水平伸缩性,能使数据在生产环境变得更有价值。Elasticsearch 的实现原理主要分为以下几个步骤,首先用户将数据提交到Elasticsearch 数据库中,再通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据,当用户搜索数据时候,再根据权重将结果排名,打分,再将返回结果呈现给用户。
ES 核心概念
问题:
es 如何去存储数据? 数据结构是什么?如何实现索引的?
集群,节点,索引,类型,文档,分片,映射是什么?
先来对比下mysql 和es 的数据对比
mysql | ElasticSearch |
---|---|
数据库 | 索引 (index) |
表(table) | types(最高版本被启用,8.x) |
行 rows | documents |
字段 columns | fields |
索引 > 类型 > 文档ID ,通过这个组合我们就能索引到某个具体的文档。 注意: ID不必是整数,实际上它是一个字符串。
文档
elasticsearch 是面向文档的。那么就意味着索引和搜索数据的最小单位是文档。在es 中文档有几个重要属性:
自我包含,一篇文档同时包含字段和对应的值,也即是同时包含 key:value
可以是层次型,一个文档中包含子文档,复杂的逻辑实体就是这么来的。
灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段
尽管我们可以随意的新增或者忽略某个字段,但是,每个字段的类型非常重要,比如一个年龄字段类型,可以是字符串也可以是整型。因为elasticsearch会保存字段和类型之间的映射及其他的设置。这种映射具体到每个映射的每种类型,这也是为什么在elasticsearch中。类型有时候也称为映射类型。
类型
类型是文档的逻辑容器,就想关系型数据库一样,表格是行的容器。类型中对于字段的定义称为映射,比如name 映射为字符串类型。我们说文档是无模式的,他们不需要拥有映射中所定义的所有字段,比如新增一个字段,那么elasticsearch是如何做的?es 会自动把新字段加入映射,但是这个字段的不确定他是什么类型,es就开始猜,如果这个值是18 ,那么es会认为它是整形。但是es也可能猜不对,所有最安全的方式就是提前定义好所需要的映射,这点跟关系型数据库了,先定义好字段,然后再使用,别整出cbug了。
题外话: 这个从7.x 已经被移除。
索引
就是数据库。索引存储了映射类型的字段和其他设置,然后我们存储到各个分片上。