Mysql是关系数据库。mysql
范式设计主要是避免冗余,以及数据不一致。反范式设计主要是避免多表链接,增长了冗余。面试
主键是一个表中一行数据的惟一标识。 外键则是值某一列的键值是其余表的主键,外键的做用通常用来做为两表链接的键,而且保证数据的一致性。redis
数据库的锁用来进行并发控制,排它锁也叫写锁,共享锁也叫行锁,根据不一样粒度能够分为行锁和表锁。sql
存储过程是对sql语句进行预编译而且以文件形式包装为一个能够快速执行的程序。可是缺点是不易修改,稍微改动语句就须要从新开发储存过程,优势是执行效率快。视图就是对其余一个或多个表进行从新包装,是一个外观模式,对视图数据的改动也会影响到数据报自己。数据库
事务的四个性质:原子性,一致性,持久性,隔离性。缓存
原子性:一个事务中的操做要么所有成功要么所有失败。服务器
一致性:事务执行成功的状态都是一致的,即便失败回滚了,也应该和事务执行前的状态是一致的。数据结构
隔离性:两个事务之间互不相干,不能互相影响。架构
事务的隔离级别 读未提交:事务A和事务B,A事务中执行的操做,B也能够看获得,由于级别是未提交读,别人事务中还没提交的数据你也看获得。这是没有任何并发措施的级别,也是默认级别。这个问题叫作脏读,为了解决这个问题,提出了读已提交。并发
读已提交:事务A和B,A中的操做B看不到,只有A提交后,在B中才看获得。虽然A的操做B看不到,可是B能够修改A用到的数据,致使A读两次的数据结果不一样。这就是不可重读问题。
可重复读:事务A和B,事务A和B,A在数据行上加读锁,B虽然看获得可是改不了。因此是可重复读的,可是A的其余行仍然会被B访问并修改,因此致使了幻读问题。
序列化:数据库强制事务A和B串行化操做,避免了并发问题,可是效率比较低。
后面能够看一下mysql对隔离级别的实现。
索引的做用就和书的目录相似,好比根据书名作索引,而后咱们经过书名就能够直接翻到某一页。数据表中咱们要找一条数据,也能够根据它的主键来找到对应的那一页。固然数据库的搜索不是翻书,若是一页一页翻书,就至关因而全表扫描了,效率很低,因此人翻书确定也是跳着翻。数据库也会基于相似的原理"跳着”翻书,快速地找到索引行。
MySQL是oracle公司的免费数据库,做为关系数据库火了好久了。因此咱们要学他。
MySQL数据库的架构能够分为客户端,服务端,存储引擎和文件系统。
详细能够看下架构图,我稍微总结下
最高层的客户端,经过tcp链接mysql的服务器,而后执行sql语句,其中涉及了查询缓存,执行计划处理和优化,接下来再到存储引擎层执行查询,底层实际上访问的是主机的文件系统。
复制代码
1 登陆mysql
mysql -h 127.0.0.1 -u 用户名 -p
2 建立表 语法仍是比较复杂的,以前有腾讯面试官问这个,而后答不上来。
CREATE TABLE `user_accounts` (
`id` int(100) unsigned NOT NULL AUTO_INCREMENT primary key,
`password` varchar(32) NOT NULL DEFAULT '' COMMENT '用户密码',
`reset_password` tinyint(32) NOT NULL DEFAULT 0 COMMENT '用户类型:0-不须要重置密码;1-须要重置密码',
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机',
`create_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
`update_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
-- 建立惟一索引,不容许重复
UNIQUE INDEX idx_user_mobile(`mobile`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8
复制代码
3 crud比较简单,不谈
4 join用于多表链接,查询的一般是两个表的字段。
union用于组合同一种格式的多个select查询。
6 聚合函数,通常和group by一块儿使用,好比查找某部门员工的工资平均值。 就是select AVE(money) from departmentA group by department
7 创建索引
惟一索引(UNIQUE) 语法:ALTER TABLE 表名字 ADD UNIQUE (字段名字)
添加多列索引 语法:
ALTER TABLE table_name ADD INDEX index_name ( column1, column2, column3)
8 修改添加列
添加列 语法:alter table 表名 add 列名 列数据类型 [after 插入位置];
删除列 语法:alter table 表名 drop 列名称;
9 清空表数据 方法一:delete from 表名; 方法二:truncate from "表名";
DELETE:1. DML语言;2. 能够回退;3. 能够有条件的删除;
TRUNCATE:1. DDL语言;2. 没法回退;3. 默认全部的表内容都删除;4. 删除速度比delete快。
下面咱们讨论的是innodb的存储原理
innodb的存储引擎将数据存储单元分为多层。按此不表
MySQL中的逻辑数据库只是一个shchme。事实上物理数据库只有一个。
mysql使用两个文件分别存储数据库的元数据和数据库的真正数据。
数据页结构 页是 InnoDB 存储引擎管理数据的最小磁盘单位,而 B-Tree 节点就是实际存放表中数据的页面,咱们在这里将要介绍页是如何组织和存储记录的;首先,一个 InnoDB 页有如下七个部分:
每个页中包含了两对 header/trailer:内部的 Page Header/Page Directory 关心的是页的状态信息,而 Fil Header/Fil Trailer 关心的是记录页的头信息。
也就是说,外部的h-t对用来和其余页造成联系,而内部的h-t用来是保存内部记录的状态。
复制代码
User Records 就是整个页面中真正用于存放行记录的部分,而 Free Space 就是空余空间了,它是一个链表的数据结构,为了保证插入和删除的效率,整个页面并不会按照主键顺序对全部记录进行排序,它会自动从左侧向右寻找空白节点进行插入,行记录在物理存储上并非按照顺序的,它们之间的顺序是由 next_record 这一指针控制的。
也就是说,一个页中存了很是多行的数据,而每一行数据和相邻行使用指针进行链表链接。
复制代码
1 MySQL的innodb支持聚簇索引,myisam不支持聚簇索引。
innodb在建表时自动按照第一个非空字段或者主键创建聚簇索引。mysql使用B+树创建索引。
每个非叶子结点只存储主键值,而叶子节点则是一个数据页,这个数据页就是上面所说的存储数据的page页。
一个节点页对应着多行数据,每一个节点按照顺序使用指针连成一个链表。mysql使用索引访问一行数据时,先经过log2n的时间访问到叶子节点,而后在数据页中按照行数链表执行顺序查找,直到找到那一行数据。
2 b+树索引能够很好地支持范围搜索,由于叶子节点经过指针相连。
explain主要用于检查sql语句的执行计划,而后分析sql是否使用到索引,是否进行了全局扫描等等。
mysql慢查询日志能够在mysql的,my.cnf文件中配置开启,而后执行操做超过设置时间就会记录慢日志。
好比分析一个sql:
explain查看执行计划
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE vote_record \N ALL votenum,vote \N \N \N 996507 50.00 Using where
仍是没用到索引,由于不符合最左前缀匹配。查询须要3.5秒左右
最后修改一下sql语句
EXPLAIN SELECT * FROM vote_record WHERE id > 0 AND vote_num > 1000;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE vote_record \N range PRIMARY,votenum,vote PRIMARY 4 \N 498253 50.00 Using where
用到了索引,可是只用到了主键索引。再修改一次
EXPLAIN SELECT * FROM vote_record WHERE id > 0 AND vote_num = 1000;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE vote_record \N index_merge PRIMARY,votenum,vote votenum,PRIMARY 8,4 \N 51 100.00 Using intersect(votenum,PRIMARY); Using where
用到了两个索引,votenum,PRIMARY。
复制代码
binlog就是二进制日志,用于记录用户数据操做的日志。用于主从复制。
redolog负责事务的重作,记录事务中的每一步操做,记录完再执行操做,而且在数据刷入磁盘前刷入磁盘,保证能够重作成功。
undo日志负责事务的回滚,记录事务操做中的原值,记录完再执行操做,在事务提交前刷入磁盘,保证能够回滚成功。
这两个日志也是实现分布式事务的基础。
mysql通常提供多种数据类型,int,double,varchar,tinyint,datatime等等。文本的话有fulltext,mediumtext等。没啥好说的。
sql能优化的点是在有点多。
好比基本的,不使用null判断,不使用>< 分页的时候利用到索引,查询的时候注意顺序。
若是是基于索引的优化,则要注意索引列是否可以使用到
1 索引列不要使用>< != 以及 null,还有exists等。
2 索引列不要使用汇集函数。
3 若是是联合索引,排在第一位的索引必定要用到,不然后面的也会失效,为何呢,由于第一列索引不一样时才会找第二列,若是没有第一列索引,后续的索引页没有意义。
举个例子。联合索引A,B,C。查询时必需要用到A,可是A的位置无所谓,只要用到就行,A,B,C或者C,B,A均可以。
4 分页时直接limit n 5可能用不到索引,假设索引列是ID,那么咱们使用where id > n limit 5就能够实现上述操做了。
复制代码
innodb支持行级锁和事务,而myisam只支持表锁,它的全部操做都须要加锁。
1 锁
锁能够分为共享锁和排它锁,也叫读锁和写锁。
select操做默认不加锁,须要加锁时会用for update加排它锁,或者用in share mode表示加共享锁。
这里的锁都是行锁。
innodb会使用行锁配合mvcc一同完成事务的实现。
而且使用next-key lock来实现可重复读,而没必要加表锁或者串行化执行。
复制代码
2 MVCC
MVCC是多版本控制协议。
经过时间戳来判断前后顺序,而且是无锁的。可是须要额外存一个字段。
读操做比较本身的版本号,自动读取比本身版本号新的版本。不读。
写操做自动覆盖写版本号比本身的版本号早的版本。不然不写。
这样保证必定程度上的一致性。
MVCC比较好地支持读多写少的情景。
可是偶尔须要加锁时才会进行加锁。
复制代码
3 事务
因此看看innodb如何实现事务的。
首先,innodb的行锁是加在索引上的,由于innodb默认有聚簇索引,但实际上的行锁是对整个索引节点进行加锁,锁了该节点全部的行。
看看innodb如何实现隔离级别以及解决一致问题
未提交读,会致使脏读,没有并发措施
已提交读,写入时须要加锁,使用行级写锁锁加锁指定行,其余事务就看不到未提交事务的数据了。可是会致使不可重读,
可重复读:在原来基础上,在读取行时也须要加行级读锁,这样其余事务不能修改这些数据。就避免了不可重读。
可是这样会致使幻读。
序列化:序列化会串行化读写操做来避免幻读,事实上就是事务在读取数据时加了表级读锁。
复制代码
可是实际上。mysql的新版innodb引擎已经解决了幻读的问题,而且使用的是可重复读级别就能解决幻读了。
实现的原理是next-key lock。是gap lock的增强版。不会锁住全表,只会锁住被读取行先后的间隙行。
分库分表的方案比较多,首先看下分表。
当一个大表没办法继续优化的时候,可使用分表,横向拆分的方案就是把一个表的数据放到多个表中。通常能够按照某个键来分表。好比最经常使用的id,1-100w放在表一。100w-200w在表二,以此类推。
若是是纵向分表,则能够按列拆分,好比用户信息的字段放在一个表,用户使用数据放在另外一个表,这其实就是一次性拆表了。
分库的话就是把数据表存到多个库中了,和横向分表的效果差很少。
若是只是单机的分表分库,其性能瓶颈在于主机。
咱们须要考虑扩展性,因此须要使用分布式的数据库。
==分布式数据库解决方案mycat==
mycat是一款支持分库分表的数据库中间件,支持单机也支持分布式。
首先部署mycat,mycat的访问方式和一个mysqlserver是相似的。里面能够配置数据库和数据表。
而后在mycat的配置文件中,咱们能够指定分片,好比按照id分片,而后在每一个分片下配置mysql节点,能够是本地的数据库实例也能够是其余主机上的数据库。
这样的话,每一个分片都能找到对应机器上的数据库和表了。
用户链接mycat执行数据库操做,实际上会根据id映射到对应的数据库和表中,
复制代码
主从复制大法好,为了不单点mysql宕机和丢失数据,咱们通常使用主从部署,主节点将操做日志写入binlog,而后日志文件经过一个链接传给从节点的relaylog。从节点定时去relaylog读取日志,而且执行操做。这样保证了主从的同步。
读写分离大法好,为了不主库的读写压力太大,因为业务以读操做为主,因此主节点通常做为主库,读节点做为从库,从库负责读,主库负责写,写入主库的数据经过日志同步给从库。这样的部署就是读写分离。
使用mycat中间件也能够配置读写分离,只需在分片时指定某个主机是读节点仍是写节点便可。
分布式关系数据库无非就是关系数据库的分布式部署方案。
真正的分布式数据库应该是nosql数据库,好比基于hdfs的hbase数据库。底层就是分布式的。
redis的分布式部署方案也比较成熟。