数据库
- 增删查改、分页
- 索引
- 并发
- 事务
- 锁
- 存储引擎
- 分布式
- 分库分表
- 读写分离
- 主从复制
- 分布式事务
- 集群
- redis和memcached
数据库的三种模式
- 模式:所有基本表构成了数据库的模式,也叫关系模式。(基本表)
- 外模式:视图与部分基本表构成了数据库的外模式。也叫子模式。(视图)
- 内模式:数据库的存储文件与其索引文件构成了关系数据库的内模式,也称为存储模式。
数据查询
数据查询一般格式:
select [ALL|DISTINCT] <目标列表达式列表> , [<目标列表达式列表>]...
from 表名或视图名,| (SELECT 语句) [AS] <别名>
[where <条件表达式>]
[group by <分组表达式> [having <条件>]]
[order by <排序表达式>[ASC|DESC]]
目标列表达式不仅可以是算术表达式,还可以是字符串常量,函数等,用户可以通过指定别名来改变查询结果的列标题,这对于含算术表达式、常量、函数名的目标表达式尤为有用。
数据库分页查询语句
- select * from table WHERE … LIMIT 10; #返回前10行
- select * from table WHERE … LIMIT 0,10; #返回前10行
- select * from table WHERE … LIMIT 10,20; #返回第10-20行数据
数据库设计三大范式
- 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。(不可再分)
- 第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。(完全依赖)
- 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。 (直接依赖)
数据库事务
- 概念
所谓事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
- ACID
事务具有4个基本特征,分别是:
- 原子性(Atomicity):原子性是指事务是一个不可再分割的工作单元,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency):一致性是指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
- 隔离性(Isolation):多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。
- 持久性(Duration):持久性,意味着在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
- 事务并发引起的问题
- 脏读(Dirty Read):脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
- 不可重复读(Unrepeatable Read):一个事务前后多次读取同一数据,但数据值不一致。(数据被其他事务修改)
- 幻读(Phantom Read):一个事务前后多次读取同一数据,但数据值不一致。(其他事务新增或者删除了数据)
- 事务隔离级别
\ | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
Serializable | × | × | × |
总结:
- 未提交读:事务可以读取另一个未提交事务的数据
- 已提交读:事务要等另一个事务提交后才能读取数据
- 可重复读:事务结束前,不允许其他事务进行修改操作(不包括插入数据)
- 可串行话:事务串行化执行,但效率低下,比较消耗数据库性能
大多数数据库默认事务隔离级别是已提交读,如oracle,sql server
Mysql的默认隔离级别是已重复读
数据库索引
索引的应用场景
-
当数据多且字段值有相同的值得时候用普通索引。
-
当字段多且字段值没有重复的时候用唯一索引。
-
当有多个字段名都经常被查询的话用复合索引。
-
普通索引不支持空值,唯一索引支持空值。
-
但是,若是这张表增删改多而查询较少的话,就不要创建索引了,因为如果你给一列创建了索引,那么对该列进行增删改的时候,都会先访问这一列的索引,
-
若是增,则在这一列的索引内以新填入的这个字段名的值为名创建索引的子集,
-
若是改,则会把原来的删掉,再添入一个以这个字段名的新值为名创建索引的子集,
-
若是删,则会把索引中以这个字段为名的索引的子集删掉。
-
所以,会对增删改的执行减缓速度,
-
所以,若是这张表增删改多而查询较少的话,就不要创建索引了。
-
更新太频繁地字段不适合创建索引。
-
不会出现在where条件中的字段不该建立索引。
索引特点
○ 可以加快数据库的检索速度
○ 降低数据库插入、修改、删除等维护的速度
○ 只能创建在表上,不能创建到视图上
○ 既可以直接创建又可以间接创建
○ 可以在优化隐藏中使用索引
○ 使用查询处理器执行SQL语句,在一个表上,一次只能使用一个索引
索引的优点和缺点
- 索引的优点
○ 创建唯一性索引,保证数据库表中每一行数据的唯一性
○ 大大加快数据的检索速度,这是创建索引的最主要的原因
○ 加速数据库表之间的连接,特别是在实现数据的参考完整性方面特别有意义
○ 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
○ 通过使用索引,可以在查询中使用优化隐藏器,提高系统的性能 - 索引的缺点
○ 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加
○ 索引需要占用物理空间,除了数据表占用数据空间之外,每一个索引还要占一定的物理空间,如果建立聚簇索引,那么需要的空间就会更大
○ 当对表中的数据进行增加、删除和修改的时候,索引也需要维护,降低数据维护的速度
索引的分类
○ 直接创建索引和间接创建索引
○ 普通索引和唯一性索引
○ 单个索引和复合索引
○ 聚簇索引和非聚簇索引
聚簇索引和非聚簇索引的区别:非聚簇索引存放的是指向数据的指针(主键),而聚簇索引存放的是数据
- 普通索引index :加速查找
- 唯一索引
主键索引:primary key :加速查找+约束(不为空且唯一)
唯一索引:unique:加速查找+约束 (唯一) - 联合索引
- primary key(id,name):联合主键索引
- unique(id,name):联合唯一索引
- index(id,name):联合普通索引
- 全文索引fulltext :用于搜索很长一篇文章的时候,效果最好。
- 空间索引spatial :了解就好,几乎不用
索引选择原则
○ 为经常出现在关键字order by、group by、distinct后面的字段,建立索引。
○ 在union等集合操作的结果集字段上,建立索引。其建立索引的目的同上。
○ 为经常用作查询选择的字段,建立索引。
○ 在经常用作表连接的属性上,建立索引。
○ 考虑使用索引覆盖。对数据很少被更新的表,如果用户经常只查询其中的几个字段,可以考虑在这几个字段上建立索引,从而将表的扫描改变为索引的扫描。
索引失效
○ 如果条件中有or,即使其中有条件带索引也不会使用(这就是问什么尽量少使用or的原因)
○ 对于多列索引,不是使用的第一部分,则不会使用索引
○ like查询是以%开头
○ 如果列类型是字符串,那一定要在条件中使用引号引起来,否则不会使用索引
○ 如果mysql估计使用全表扫秒比使用索引快,则不适用索引。
联合索引最左匹配原则
- 最左前缀匹配原则,非常重要的原则,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的查询优化器会帮你优化成索引可以识别的形式
数据库存储引擎比较
- InnoDB
- MyISAM
- Memory
MyISAM和InnoDB引擎的区别
-
主要区别
○ MyISAM是非事务安全型的,而InnoDB是事务安全型的。
○ MyISAM锁的粒度是表级,而InnoDB支持行级锁定。
○ MyISAM支持全文类型索引,而InnoDB不支持全文索引。
○ MyISAM相对简单,所以在效率上要优于InnoDB,小型应用可以考虑使用MyISAM。
○ MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去不少的麻烦。
○ InnoDB表比MyISAM表更安全,可以在保证数据不会丢失的情况下,切换非事务表到事务表(alter table tablename type=innodb)。 -
应用场景
○ MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。
○ InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。 -
各引擎支持的索引
索引 | MyISAM | InnoDB | MeMory |
---|---|---|---|
B-Tree | 支持 | 支持 | 支持 |
Hash | 不支持 | 不支持 | 支持 |
R-Tree | 支持 | 不支持 | 不支持 |
Full-Text | 不支持 | 不支持 | 不支持 |
Redis
Redis 三种集群模式
- 主从模式
- 哨兵模式
- 集群
redis支持的数据结构
string list hash set zset
redis线程模型
redis是单线程实现。
redis 提供的持久机制
redis 支持rdb和afo两种持久机制。rdb是定时的持久机制,宕机有可能会存在数据丢失。aof是基于操作日志的持久机制。
redis事务
redis提供了一些在一定程度上支持线程安全和事务的命令。例如:multi/exec watch inc等。但是redis的事务并不支持回滚,即可以两个命令可以同时提交执行,但是如果有失败,成功的也不会回滚
redis数据淘汰策略
在 redis 中,允许用户设置最大使用内存大小通过配置redis.conf中的maxmemory这个值来开启内存淘汰功能,在内存限定的情况下是很有用的。
redis lru数据淘汰机制
再数据集合中随机挑选几个键值对,取出其中lru最大的键值对淘汰。所以redis并不是保证淘汰的是最近最少使用的,而是随机挑选的几个键值对中的最近最少使用的
过期策略的实现
常见的过期策略有三种,定时,惰性,定期。redis使用了惰性和定期策略,memcached只使用了惰性策略
- 定时策略:指定在多少时间之后过期。
- 惰性策略:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null
- 定期策略:每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过期key操作。java实现的话就是起个定时任务而已
缓存穿透
缓存穿透指的是使用不存在的key进行大量的高并发查询,这导致缓存无法命中,每次请求都要穿透到后端数据库系统进行查询,数据库压力过大。
常用解决方案:将空值缓存起来。
其他解决方案:使用布隆过滤器(guava 19开始已支持布隆过滤器),布隆过滤器原理与应用
缓存雪崩
缓存雪崩指缓存服务器重启或者大量缓存集中在某一个时间段内失效
常用解决办法:对不同的数据使用不同的失效时间,甚至对相同的数据、不同的请求使用不同的失效时间。
缓存优秀实践
1)使用前对数据大小进行评估,包括缓存的数据结构、大小、数量、失效时间
2)根据业务进行隔离,尽量不要多个业务共用一个缓存实例
3)缓存的key尽可能的设定缓存失效时间,且失效时间不能集中在某一点
4)缓存尽量不要存大对象
5)写缓存时一定要写入完全正确的数据。如果缓存数据部分有效,部分无效,宁可放弃缓存
6)一定要对操作超时时间进行设置。一般我们设计缓存作为加速数据库读取的手段,也会对缓存操作做降级处理,因此推荐使用更短的缓存超时时间,如果一定要给出一个数字,则希望是100毫秒以内
redis相比memcached有哪些优势?
(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
(2) redis的速度比memcached快很多
(3) redis可以持久化其数据
redis 最适合的场景
- 会话缓存(Session Cache) 最常用的一种使用Redis的情景是会话缓存(session cache)
- 全页缓存(FPC) 除基本的会话token之外,Redis还提供很简便的FPC平台
- 队列 Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用
- 排行榜/计数器 Redis在内存中对数字进行递增或递减的操作实现的非常好
- 发布/订阅 最后(但肯定不是最不重要的)是Redis的发布/订阅功能
使用Redis有哪些好处?
(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除