简介:
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。
因MyISAM 和 InnoDB 是主要引擎所以多做概述
MyISAM:
Myisam只支持表级锁,用户在操作 myisam 表时,select、update、delete、insert、语句都会给表自动加锁,如果加锁以后的表满足 insert 并发的情况下,可以在表的尾部插入新的数据。也可以通过 locktable 命令来锁表,这样的操作主要是可以模仿事务,但消耗特别大。
因为MyISAM表有无法处理事务,所以它只适合在一下几种情况下使用
1.选择密集型的表。MyISAM存储引擎在筛选大量数据时非常迅速,这是它最突出的优点。
2.插入密集型的表。MyISAM的并发插入特性允许同时选择和插入数据。例如:MyISAM存储引擎很适合管理邮件或Web服务器日志数据。
InnoDB:
1.更新密集的表。InnoDB存储引擎特别适合处理多重并发的更新请求。
2.事务。InnoDB存储引擎是支持事务的标准MySQL存储引擎。
3.自动灾难恢复。与其它存储引擎不同,InnoDB表能够自动从灾难中恢复。
4.外键约束。MySQL支持外键的存储引擎只有InnoDB。
5.支持自动增加列AUTO_INCREMENT属性。
MyISAM & InnoDB 差异:
- 自增长差异:
MyISAM 引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,
它可以根据前面几列进行排序后递增。
InnoDB 引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列
- 主键差异:
MyISAM 允许没有任何索引和主键的存在,
MyISAM 的索引都是保存行的地址
InnoDB 如果没有设定主键 或者 非空唯一索引,就会自动生成一个6字节的主键(用户不可见)
InnoDB 的数据是主索引的一部分,附加索引保存的是主索引的值。
- count()函数差异:
MyISAM 保存有表的总行数,如果 select count(*) from table; 会直接取出该值
InnoDB 没有保存表的总行数,如果使用 select count(*) from table; 就会遍历整个表,消耗相当之大,但是加了 where 条件后,MyIASM 和 InnoDB 的处理方式都一样
- 全文索引差异:
MyISAM 支持 FullText 类型的全文索引
InnoDB 不支持 FullText 类型的全文索引,但是 InnoDB 可以使用
sphinx 插件支持全文索引,并且效果更好
delete from table
使用这条命令时,InnoDB不会从新建立表,而实一条条的删除数据,在InnoDB上如果要清空保存有大量数据的表,最好不要使用这条命令。(推荐使用 truncate table,不过需要用户有 diop 此表的权限)
- 索引保留位置差异:
MYISAM 的索引以表名 + .MYI 文件分别保存
InnoDB 的索引和数据一起保存在 表空间里
- 存储疫情选择差异:
MyISAM B+tree
InnoDB B-tree
12345678910111213141516171819202122232425262728293031323334353637
MEMORY /meməri/ -- 买么瑞
:
使用MEMORY引擎主要是因为速度,好处就在MEMORY采用的逻辑存储是系统内存,极大的提高了储存数据表的性能; 坏处就是当mysqld守护进程崩溃时,所有的Memory数据都会丢失。
一般在以下几种情况下使用Memory存储引擎:
1.目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory表的最大大小。
2.如果数据是临时的,而且必须立即使用,那么就可以存放在内存表中。
3.存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。
MERGE /mɜːdʒ/ -- 么耳吱
:
MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表结构必须完全相同,所以就相当于一个集合器。比起其他储存引擎MERGE不是很优秀,但是在某些情况下MERGE还是非常的有用。对于服务器日志这种信息,一般常用的存储策略是将数据分成很多表,每个名称与特定的时间端相关。
ARCHIVE /'ɑ:kaiv/ -- 阿尔铠武
:
Archive是归档的意思,在归档之后很多的高级功能就不再支持了,仅仅支持最基本的插入和查询两种功能。在MySQL 5.5版以前,Archive是不支持索引,但是在MySQL 5.5以后的版本就开始支持索引了。Archive拥有很好的压缩机制,它使用zlib压缩库,在记录被请求时会实时压缩,所以它经常被用来当做仓库使用。
BDB(BerkeleyDB)
EXAMPLE /ɪɡˈzæmpl/ -- 诶个曾伯
FEDERATED /'fɛdə,retɪd/ -- F艾 的瑞der
CSV
BLACKHOLE
事务(Transaction)是数据库区别于文件系统的重要特性之一,事务会把数据库从一种一致性状态转换为另一种一致性状态。
在数据库提交时,可以确保要么所有修改都已保存,要么所有修改都不保存。
MySQL数据库默认采用自动提交(autocommit)模式, 也就是说修改数据(insert、update、delete)的操 作会自动的触发事务,完成事务的提交或者回滚
开启事务使用 begin 或者 start transaction;
回滚事务使用 rollback;
pymysql 里面的 conn.commit() 操作就是提交事务
pymysql 里面的 conn.rollback() 操作就是回滚事务
12345
未提交读: 脏读(READ UNCOMMITTED) 读未提交
(存在4个问题 脏读、不可重复读、幻读、更新丢失)
解决方法:
将数据库事务隔离级别调整到 Read_Commited 读已提交
提交读: 不可重复读(READ COMMITTED)
(不可重复读、幻读、丢失更新)
解决方法:
将数据库事务隔离级别调整到 Repeatable_read 可重复 读
可重复读: 幻读(REPEATABLE READ):这是MySQL的默认事务隔离级别
简易版
指 事务A 对一个表中的数据进行了修改,而且该修改涉及到表中的所有数据行;同时另一个 事务B 也在修改表中的数据,该修改像表中插入一条新数据。那么经过操作之后,操作 事务A 的用户就会发现表中还有没修改的数据行,就像发觉了幻觉一样,故 幻读。
(存在两个问题 幻读、丢失更新)
解决方法
将数据库事务隔离级别调整到 Serializable_read 串行读
可串行读(SERIALIZABLE) 序列化&串行读
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommitted(未提交读) | √ | √ | √ |
read committed(提交读) | × | √ | √ |
repeatable read(可重复读) | × | × | √ |
serializable (可串行化) | × | × | × |
级别高低:脏读 < 不可重复读 < 幻读
所以只要是设置了 最高级别 Serializable 就解决了 前三个问题了,当时 他的资源消耗是最致命的。
什么是锁?
锁是协调多个进程或线程并发访问某一资源的一种机制。在数据库当中,除了传统的计算资源(CPU、RAM、I/O等等)的争用之外,数据也是一种供许多用户共享访问的资源。如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素。从这一角度来说,锁对于数据库而言就显得尤为重要。
在 Mysql中 有两种锁:Lock 和 Latch
Latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差,在InnoDB引擎中,Latch又可以分为mutex(互斥量)和 rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。
Lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。
关于Latch更详细的讲解可以参考:关于MySQL latch争用深入分析与判断,本文主要关注的是Lock锁。
对数据的操作其实只有两种,也就是读和写,而数据库在实现锁时,也会对这两种操作使用不同的锁;InnoDB 实现了标准的行级锁,也就是共享锁(Shared Lock)和互斥锁(Exclusive Lock)。
共享锁之间是兼容的,而互斥锁与其他任意锁都不兼容:
共享锁代表了读操作、互斥锁代表了写操作,所以我们可以在数据库中并行读,但是只能串行写,只有这样才能保证不会发生线程竞争,实现线程安全。
Lock锁根据粒度主要分为表锁、页锁和行锁。不同的存储引擎拥有的锁粒度都不同。
表级别的锁定是MySQL各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免困扰我们的死锁问题。
当然,锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并发度大打折扣。
使用表级锁定的主要是MyISAM,MEMORY,CSV等一些非事务性存储引擎。
页级锁定是MySQL中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见。页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间。另外,页级锁定和行级锁定一样,会发生死锁。
在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。
使用页级锁定的主要是BerkeleyDB存储引擎。
行级锁定最大的特点就是锁定对象的粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。
虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。
使用行级锁定的主要是InnoDB存储引擎。
总结
意向锁
上节提到InnoDB 支持多种粒度的锁,也就是行锁和表锁。为了支持多粒度锁定,InnoDB 存储引擎引入了意向锁(Intention Lock)。
那什么是意向锁呢?我们在这里可以举一个例子:如果没有意向锁,当已经有人使用行锁对表中的某一行进行修改时,如果另外一个请求要对全表进行修改,那么就需要对所有的行是否被锁定进行扫描,在这种情况下,效率是非常低的;不过,在引入意向锁之后,当有人使用行锁对表中的某一行进行修改之前,会先为表添加意向互斥锁(IX),再为行记录添加互斥锁(X),在这时如果有人尝试对全表进行修改就不需要判断表中的每一行数据是否被加锁了,只需要通过等待意向互斥锁被释放就可以了。
与上一节中提到的两种锁的种类相似的是,意向锁也分为两种:
以上原文出处:
https://blog.csdn.net/bruceleenumberone/article/details/81865045
举例:
我们收藏购物车 就是乐观锁。假如商品只有1件的时候,所有人都会加入购物车,但是购买只会有一个人
#### 乐观锁实现加一操作代码
# 我们可以看到,只有当对数量-1操作时才会加锁,只有当程序中值和数据库中的值相等时才正真执行。
'''
//不加锁
select id,name,stock where id=1;
//业务处理
begin;
update shop set stock=stock-1 where id=1 and stock=stock;
commit;
'''
12345678910
举例:
购买商品的付款时间就是悲观锁,购买商品 30分钟付款时间 就是开的悲观锁,假设商品只有一个,这三个小时我买了没付钱、最后订单取消。这30分钟你都不会购买到次商品
#### 悲观锁实现加一操作代码
# 我们可以看到,首先通过begin开启一个事物,在获得shop信息和修改数据的整个过程中都对数据加锁,保证了数据的一致性。
'''
begin;
select id,name,stock as old_stock from shop where id=1 for update;
update shop set stock=stock-1 where id=1 and stock=old_stock;
commit
'''
12345678
举例:
如果我们进入洗手间是为了上厕所,那么就不能允许任何人进来了。
这就是排他锁,也叫写锁,就是我们对数据进行写操作的时候,要想获得写锁,获得写锁的事务既可以写数据也可以读数据。
当时,如果数据库已经被别人增加了排他锁,那么后面的事务是无法在获得该数据库得任何锁得。
也就是说,如果事务A对 数据加上了排他锁后,则其他事务不能在对 数据 加任何类型得封锁。获准排他锁得事务既能读数据,又能修改数据。
1234
举例:
如果我们进家里的洗手间只是想洗手,一般不会锁门,其他人也可以来洗手,但是 其他人是不可以进来上厕所的。
这就是共享锁,也叫读锁,就是我们对数据进行读取操作的时候,其实是不会改变数据的值的。所以我们可以给数据库增加读锁,获得读锁的事务j就可以读取数据了。
当数据库已经被别人增加了读锁的时候,其他新来的事务y也可以读数据,但是不能写。
也就是说,如果 事务A 对数据加上了 共享锁后,则 其他事务只能对 数据 再加共享锁,不能加排他锁。获取共享锁的事务只能读数据,不能修改数据。
1234
Btree是一种多路自平衡搜索树,它类似普通的二叉树,但是Btree允许每个节点有更多的子节点。Btree示意图如下:
由上图可知 Btree 的一些特点:
B+树是B树的变体,也是一种多路平衡查找树,B+树的示意图为:
由图可看出B+tree的特点 同时也是 Btree 和 B+tree的区别
在数据存储的索引结构上 Btree 更偏向于 纵向深度的存储数据 而 B+tree 更青睐于 横向广度的存储数据。
参考原址-(写的非常好)
MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
主从复制原址
mysql-binlog是MySQL数据库的二进制日志,用于记录用户对数据库操作的SQL语句((除了数据查询语句)信息。可以使用mysqlbin命令查看二进制日志的内容。
binlog的格式也有三种:STATEMENT、ROW、MIXED 。
无论是增量备份还是主从复制,都是需要开启mysql-binlog日志,最好跟数据目录设置到不同的磁盘分区,可以降低io等待,提升性能;并且在磁盘故障的时候可以利用mysql-binlog恢复数据。
1. 数据库的表设计
2. 索引
当把一张表的某列设置为主键的时候,则该列就是主键索引。
当表的某列被指定为unique约束时,这列就是唯一索引
一般来说,普通索引是先创建表,然后创建普通索引。
全文索引,主要是针对文件,比如文章的索引全文索引针对MyISAM有用,针对innodb没有用
3. 表的分割
水平分割:
大数据量的表,我们在提供检索的时候,应该根据业务的需求,找到表的标准,并在检索页面约束用户的检索方式,而且要配合分页,
案例:大数据量的用户表
三张表:A, B, C
create table A(
id int unsigned not null primary key,/* 这个id不能设置自增长 */
name varchar(32)not null default'',
pwd varchar(32)not null default''
)engine = myisam default charset = utf8;
create table B(
id int unsigned not null主键,/ *这个id不能设置自增长* /
name varchar(32)not null default'',
pwd varchar(32)not null default''
)engine = myisam default charset = utf8;
create table C(
id int unsigned not null主键,/ *这个id不能设置自增长* /
name varchar(32)not null default'',
pwd varchar(32)not null default''
)engine = myisam default charset = utf8;
123456789101112131415161718192021222324252627282930
垂直分割:
把某个表的某些字段,这些字段,在查询时候并不关系,但是数据量很大,我们建议将这些字段放到一个表中,从而提高效率,
Mysql优化原文链接
Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
优点:
上面有介绍
缺点
- 内存限制,不能用作海量数据
1. redis中所有数据结构都以唯一的key字符串作为名称,然后通过这个唯一的key来获取对应的value`
`2. 不同的数据类型数据结构差异就在于value的结构不一样
1. 字符串(string)
2. list(列表)
3. hash(字典)
4. set ( 集合对象 )
5. Sorted set (有序集合对象)
前言
由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。
RDB:
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
AOF:
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
二者之间的优缺点
RDB的优势
RDB的劣势
AOF的优势
AOF的劣势
二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。
redis有哪几种集群?`
`主从模式 哨兵模式 codis
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。
默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
主从复制过程大体可以分为3个阶段:连接建立阶段(即准备阶段)、数据同步阶段、命令传播阶段。
在从节点执行 slaveof 命令后,复制过程便开始运作,下面图示大概可以看到,
从图中可以看出复制过程大致分为6个过程
主从复制参考原址
注:redis主节点Master挂掉时,运维让从节点Slave接管(redis主从默认无法自动切换,需要运维手动切换)
从服务器把有的数据全部丢弃,让主服务把所有数据全部发给他
注:Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
全量同步:从服务器把有的数据全部丢弃,让主服务把所有数据全部发给他
Redis主从同步参考地址
哨兵模式如何解决主从问题?
当用Redis做主从方案时,假如master宕机,Redis本身无法自动进行主备切换
而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。
哨兵是redis集群架构中非常重要的一个组件,主要功能如下:
哨兵本身也是分布式的,作为一个哨兵集群去运行的,相互协同工作
哨兵的核心知识
法1:redis-sentinel /path/to/sentinel.conf
法2:redis-server /path/to/sentinel.conf --sentinel
# sentinel.conf 配置说明
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
12345
因为每一个配置都有一个版本号,所以以版本号最大的那个为标准:
redis的slave和master数据时完全一样的,但是有个问题,redis数据时存储在内存中
内存空间有限,所以哨兵模式不能处理大的数据量
如何解决?codis
简介
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.
codis是redis集群解决方案之一,codis是GO语言开发的代理中间件
当客户端向codis发送指令时,codis负责将指令转发给后面的redis实例来执行,并将返回结果转发给客户端
为什么会出现codis
codis部署方案
\4. 单个codis代理支撑的QPS比较有限,通过启动多个codis代理可以显著增加整体QPS
\5. 多codis还能起到容灾功能,挂掉一个codis代理还有很多codis代理可以继续服务
codis分片的原理
不同codis槽位如何同步
布隆过滤器是什么?(判断某个key一定不存在)
应用场景
布隆过滤器原理
添加:值到布隆过滤器
\1. 向布隆过滤器添加key,会使用 f、g、h hash函数对key算出一个整数索引,然后对长度取余
\2. 每个hash函数都会算出一个不同的位置,把算出的位置都设置成1就完成了布隆过滤器添加过程
查询:布隆过滤器值
\1. 当查询某个key时,先用hash函数算出一个整数索引,然后对长度取余
\2. 当你有一个不为1时肯定不存在这个key,当全部都为1时可能有这个key
\3. 这样内存中的布隆过滤器过滤掉大量不存在的row请求,然后去再磁盘进行查询,减少IO操作
删除:不支持
\1. 目前我们知道布隆过滤器可以支持 add 和 isExist 操作
\2. 如何解决这个问题,答案是计数删除,但是计数删除需要存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。
\3. 增加一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。
需要注意的是:
1.Redis的事务没有关系数据库事务提供的回滚(rollback),所以开发者必须在事务执行失败后进行后续的处理;
2.如果在一个事务中的命令出现错误,那么所有的命令都不会执行;
3.如果在一个事务中出现运行错误,那么正确的命令会被执行。
注:redis事物在遇到指令失败后,后面的指令会继续执行
mysql的rollback与redis的discard的区别:
> multi(开始一个redis事物)
incr books
incr books
> exec (执行事物)
> discard (丢弃事物)
12345
watch其实就是redis提供的一种乐观锁,可以解决并发修改问题
watch会在事物开始前盯住一个或多个关键变量,当服务器收到exec指令要顺序执行缓存中的事物队列时
redis会检查关键变量自watch后是否被修改(包括当前事物所在的客户端)
如果关键变量被人改动过,exec指令就会返回null回复告知客户端事物执行失败,这个时候客户端会选择重试
注:redis禁用在multi和exec之间执行watch指令,必须在multi之前盯住关键变量,否则会出错
> setnx lock:codehole true
.... do something critical ....
> del lock:codehole
123
> setnx lock:codehole true
> expire lock:codehole 5
.... do something critical ....
> del lock:codehole
1234
> set lock:codehole true ex 5 nx
''' do something '''
> del lock:codehole
123
待补充
写快:
写入数据存在在内存里就返回给应用程序,
而保存到硬体的操作则在后台异步完成