MYSQL
InnoDB会选择主键作为聚集索引,没有则选择第一个不包含有NULL值的唯一索引所谓主键索引,还没有则选择内置6字节长的ROWID作为隐含的聚集索引
InnoDB默认的装载因子15/16
nnoDB:
支持事务处理等
不加锁读取
支持外键
支持行锁
不支持FULLTEXT类型的索引
不保存表的具体行数,扫描表来计算有多少行
DELETE 表时,是一行一行的删除
InnoDB 把数据和索引存放在表空间里面
跨平台可直接拷贝使用
InnoDB中必须包含AUTO_INCREMENT类型字段的索引
表格很难被压缩
MyISAM:
不支持事务,回滚将造成不完全回滚,不具有原子性
不支持外键
不支持外键
支持全文搜索
保存表的具体行数,不带where时,直接返回保存的行数
DELETE 表时,先drop表,然后重建表
MyISAM 表被存放在三个文件 。frm 文件存放表格定义。 数据文件是MYD (MYData) 。 索引文件是MYI (MYIndex)引伸
跨平台很难直接拷贝
MyISAM中可以使AUTO_INCREMENT类型字段建立联合索引
表格可以被压缩
选择:
因为MyISAM相对简单所以在效率上要优于InnoDB.如果系统读多,写少。对原子性要求低。那么MyISAM最好的选择。且MyISAM恢复速度快。可直接用备份覆盖恢复。
如果系统读少,写多的时候,尤其是并发写入高的时候。InnoDB就是首选了。
两种类型都有自己优缺点,
索引提高效率:通过索引查询数据是无需遍历索引记录的,极端下为log2(n)
B+树索引和哈希索引
B+树:平衡多叉树,节点间指针连接,有序; 适合大部分场景,范围查询,匹配查询等;默认索引
哈希索引:无序, 适合等值查询。数据重复度低,。可能会建立自适应哈希索引
(B树和B+树:B树:每个节点都存储key和data,叶子节点指针为null,不包含关键字信息。。B+树:叶子节点包含全部关键字信息,及指向含有这些关键字记录的指针。自小而大顺序连接。B+树磁盘读写代价更低,所有关键字查询的路径长度相同,所以查询效率稳定。)
不建索引情况: 表记录太少,经常插入修改的表,数据重复且分布平均的表字段,经常和主字段查询单主字段索引值较多
分区从逻辑上讲只有一张表;分表则是将一张表分解成多张表;
行级锁定的优点:只存在少量的锁定冲突;回滚时只有少量的更改;可以长时间锁定单一的行
mysql优化:开启查询缓存,优化查询;限定查询数量;使用enum而不是varchar;垂直分表;
mysql中MyISAM和InnoDB的区别:
InnoDB支持事务(默认封装事务,自动提交),MyISAM不支持;
InnoDB支持外键,MyISAM不支持;
InnoDB是聚集索引,数据文件是和索引绑定一起的。必须要有主键。MyISAM是非聚集索引,数据文件分离,索引保存的是数据文件的指针;
InnoDB不保存表的具体行数,需要全表扫描,MyISAM有一个变量保存全表行数; InnoDB不支持去哪问索引,MyISAM支持
主从复制架构(将master进行操作后,日志发送给slave。(slave的数据是滞后的))
master负责写,slave负责读操作。
如果mysql的读写压力太大,主从复制架构也满足不了。可以分库(垂直拆分),分表(水平拆分)
MySQL
Mysql的binlog日志作用是用来记录mysql内部增删改查等对mysql数据库有更新的内容的记录(对数据库的改动),对数据库的查询select或show等不会被binlog日志记录;主要用于数据库的主从复制以及增量恢复。
mysql的binlog日志必须打开log-bin功能才能生存binlog日志
编辑my.cnf配置文件
1 2 |
# grep log-bin my.cnf log-bin = /data/3306/mysql-bin |
Mysqlbinlog功能是将Mysql的binlog日志转换成Mysql语句,默认情况下binlog日志是二进制文件,无法直接查看。
3、MySQL binlog的三种工作模式
(1)Row level
日志中会记录每一行数据被修改的情况,然后在slave端对相同的数据进行修改。
优点:能清楚的记录每一行数据修改的细节
缺点:数据量太大
(2)Statement level(默认)
每一条被修改数据的sql都会记录到master的bin-log中,slave在复制的时候sql进程会解析成和原来master端执行过的相同的sql再次执行
优点:解决了 Row level下的缺点,不需要记录每一行的数据变化,减少bin-log日志量,节约磁盘IO,提高新能
缺点:容易出现主从复制不一致
(3)Mixed(混合模式)
结合了Row level和Statement level的优点。 版本中的mysql中对row level模式也做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录,如果sql语句确实就是update或者delete等修改数据的语句,那么还是会记录所有行的变更。
一般来说开启二进制日志大概会有1%的性能损耗(参见MySQL官方中文手册 5.1.24版)。二进制有两个最重要的使用场景:
其一:MySQL Replication在Master端开启binlog,Mster把它的二进制日志传递给slaves来达到master-slave数据一致的目的。
其二:自然就是数据恢复了,通过使用mysqlbinlog工具来使恢复数据。
二进制日志包括两类文件:二进制日志索引文件(文件名后缀为.index)用于记录所有的二进制文件,二进制日志文件(文件名后缀为.00000*)记录数据库所有的DDL和DML(除了数据查询语句)语句事件。
索引
NoSql:性能高,扩张性强,模式灵活
Mysql:查询功能强,数据一致性高,数据安全性高,支持二级索引
索引优势:1.提高数据的检索速度,降低数据库IO成本:通过缩小表中需要查询的记录数目从而加快搜索的速度;
2.降低数据排序的成本,降低CPU小号:先将数据排序,若该子弹正好需要排序,则降低了成本;
索引劣势:1.占用存储空间:索引实际上也是一张表,记录 了主键和索引字段,一般以索引文件的形式存储在磁盘上;
2.降低更新表的速度:表中数据变化时,对应的索引也需要一起更新。否则索引指向的数据不对,失效;
3.优质索引创建难:需要频繁根据用户的行为和具体的业务逻辑去创建最佳的索引
索引分类:BTree(多路搜索树)
单值索引:单个列
唯一索引:值必须唯一,允许有空值;
复合索引:包含多个列,建议不超过五个。
索引使用场景:
1.主键,唯一索引
2.经常用做查询条件的字段需要创建索引;
3.经常需要排序,分组,和统计的字段需要建立索引。
4.查询中与其他表关联的字段 ,外键关系建立索引;
索引不要使用 的场景:
1.表的记录太少,百万以下不需要建立索引
2.经常增删改查的表不需要
3.数据重复且分部平均的字段。如true,false
4.频发更新的字段不适合;
5.where条件里用不到的字段;
MySql自身瓶颈:
1.CPU:cpu在饱和的时候一般在数据装入内存或从磁盘中读取数据的时候;
2.IO:磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
3.服务器硬件的性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态;
SQL优化:
1.任何在where子句中使用is null 或者is not null 的语句都不允许使用索引;(无用)
2.使用% 进行双向模糊查询的时候不要使用索引
3.Order by 中非索引项或表达式会降低性能;
4.select子句中避免使用 *
5.通过内部函数提高sql效率
6.使用表的别名,减少解析时间;
7.使用exists代替in,用not exists代替not in
8.用索引提高效率,但需要额外的空间存储,并经常修改;
9.用exists替换distinct
10.sql语句用大写的:oracle会解析sql成大写在执行
11.避免在索引列上使用计算
12.用 >= 代替 >
13.用union替换or。用union all 替换 union
14.避免改变索引列的类型:如 13 写成 ‘13’
15.优化group by,尽量使用where 代替having
Redis
String json 将对象序列化后存储到Redis,mget批量获取
Hash 存储对象
List 可以做栈,可以做队列。实时列表,消息队列
Set 集合的运算,交并差集 共同关注,共同粉丝
ZSet SortedSet 排序场景 排行榜,
string set,get,decr,incr,mget
SET name "runoob"
OK
GET name
"runoob"
hash hget,hset,hgetall
HSET myhash field1 "Hello" field2 "World"
"OK"
HGET myhash field1
"Hello"
list :lpush,rpush,lpop,rpop,lrange
lpush runoob rabitmq
(integer) 3
lrange runoob 0 10
1) "rabitmq"
set sadd,spop,smembers,sunion
sadd runoob rabitmq
(integer) 0
smembers runoob
zset zadd,zrange,zrem,zcard
zadd runoob 0 rabitmq
(integer) 0
ZRANGEBYSCORE runoob 0 1000
Redis将所有数据放到内存中:为了达到最快的读写速度,并通过异步的方式将数据写入磁盘。若不将数据放在内存中,磁盘I/O速度会英雄redis的性能。
Redis是单进程单线程的:利用队列技术奖并发访问变成串行访问,消除了传统数据库串行空值的开销。
分布式:redis支持主从模式(master将数据同步到slave,slave启动时连接master来同步时局),读写分离(通过增加slave的数量,使集群的读写性能高,但是每个节点都必须保存完整数据,集群的扩展能力受限于蛋哥节点的存储能力)
Redis和Memcache的区别:1)存储方式:内存和磁盘;2)数据支持类型:简单和复杂 3)使用底层模型不同:底层实现方式和与客户端之间通信的应用协议不同。Redis直接自己构建了VM机制,因为系统调用函数会浪费时间去移动和请求。 4)value大小:redis最大1GB,memcache只有1MB
Redis单线程:网络请求模块使用了一个线程,即一个线程处理所有网络请求;
快速执行原因:大部分请求时纯粹的内存操作;采用单线程;非堵塞IO-IO多路复用
好处:速度快;支持多类型;支持事务,操作都是原子性;可用于缓存,消息,按key设置过期时间,过期后自动删除;
主从复制:
过程原理:1.当从库和主库简历MS关系后,会向主数据库发送SYNC命令;
2.主库接收到SYNC命令后会开始在后台保存快照(RDB持久化过程)并将期间接受到的写命令缓存起来
3.当快照完成后,主Redis会讲快照文件和所有缓存的写命令发送给从Redis
4.从Redis接收到后,会载入快找文件并且执行收到的缓存的命令
5.之后,主Redis每当接收到写命令时就会将命令发送给从Redis,从而保证数据的一致性
缺点:所有的节点数据的复制和同步都由master节点处理,会造成节点压力他打,使用主从从结构来解决
Redis的两种持久化方式的优点:
RDB持久化可以再指定的时间间隔内生成数据集的时间点快照(固定时间点,适用于数据恢复)
AOF持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集(Master重启时加载AOF文件)
Redis还可以同时使用RDB和AOF,当redis重启时,他会有限使用AOF文件来还原数据集,因为AOF文件保存的数据集通常比RDB文件所保存的数据更加完整。
性能问题:Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时,对性能影响大,会间断性暂停服务。
Master AOF持久化,随着AOF文件的增大,会影响Master重启的回复速度。
AOF重写的时候回占用大量内存资源,出现短暂服务暂停现象
Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在一个局域网内
redis的并发竞争问题如何解决?
Redis为单进程单线程模式;Redis本身没有锁的概念;Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时,数据转换错误,阻塞,客户端关闭连接等问题。这些问题是由于客户端连接混乱造成的。
解决方法:
客户端角度:为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同事对客户端读写Redis操作采用内部锁synchronized
(需要应用程序自己处理资源的同步,可用synchronized或者lock)
服务器角度:利用setnx实现锁(需要用Redis的setnx命令)
redis的高级事务CAS(操作实现乐观锁)
MULTI/EXEC/DISCARD/MATCH
事务的实现特征:
事务中的所有命令都将会被串行化的顺序执行(执行期间,Redis不会再为其他客户端的请求提供任何服务,保证原子性)
Redis事务如果有某一条命令执行失败,其他命令仍然会继续执行
Redis持久化方式:快照
Redis缓存的数据一致性:分为最终一致性和强一致(不能使用缓存);
Redis的过期:定期删除:每100ms检测一下,随机检测;当读写一个过期key时,直接干掉
内存淘汰:指用户存储的一部分key被Redis自动删除,从而查不到;
缓存击穿:缓存是为了缓解数据库压力而添加的一层保护层;如果缓存失效或者一直没有利用缓存,瞬间所有的请求压力都落在数据库上,会导致数据库连接 异常;(1.后台设置定时更新缓存数据;2.分级缓存(2级缓存加锁访问数据库);3提供一个拦截机制,维护合法的key值,不合法直接返回;)
解决方案:1.bloom filter:用所有可能的查询条件生产一个bitmap,然后使用bitmap过滤;2.空值缓存:在第一次查询完不存在的数据,将该key与对 应的空值也放入缓存中,设定较短的失效时间,这样可以应对短时间的大量的该key的攻击;
缓存雪崩:缓存突然整体宕机,导致大量请求到达数据库导致崩溃,(1.给缓存加随即生效时间,避免同时集体失效; 2. 二级缓存,原始缓存失效时从拷贝缓 存中读取数据;3.利用加锁和队列方式避免过多请求同时访问服务器;)
解决方案:1.线程互斥:每个时刻只有一个线程执行请求;2.交错失效时间;
二级缓存:主要解决热点访问。结合LRU算法(最近最少使用算法;多维护一个队列,用于记录所有缓存数据被访问的历史;提高了缓存的命中率),
缺点:1.内存数据库,存储数据量有限,需要及时删除;2.修改Redis数据持久化后重新加入内容时,此时Redis无法正常运行
数据库优化
第一阶段: 优化sql和索引。成本低;
1)用慢查询日志定位执行效率低的sql语句
2)用explain分析sql的执行计划
3)确定问题,进行优化,建立索引等;
第二阶段:搭建缓存
优化sql无法解决问题时才增加缓存;(问题:缓存和数据库一致性问题;缓存击穿和雪崩问题的解决)
第三阶段:读写分离
缓存也搞不动则 主从复制,读写分离;在应用层区分读写请求或者利用线程的中间件mycat或altas做读写分离;
主从的好处:数据库备份,实现数据库负载均衡,提高数据库可用性;
第四阶段:利用分区表(所有数据还在一个表,但物理存储根据一定的规则放在不同的文件中)
第五阶段:垂直拆分;
第六阶段:水平拆分
Redis的RDB的全量持久化和AOF的增量持久化
redis的乐观锁
基于数据版本的记录机制实现的;即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过数据库表增加一个“version”字段来实现读取出数据时,将此版本号一同读出;更新时版本号+1;提交时,如果版本号大于数据库版本号则更新,否则认为是过期数据;
redis的数据类型、:
1.String:一些复杂的计数功能的缓存;
2.hash:方便操作其中的字段;单点登录(存储用户信息,以cookieId作为key,设置20分钟的缓存过期时间);
3.List:做简单的消息队列的功能;(利用lrang命令,做基于redis的分页功能, Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定)
4.set :存放一堆不重复值的集合,做全局去重的功能;利用交并差集,计算共同爱好,全部洗好,独有爱好等;
5.sorted set:多了权重参数score,集合中的元素可以按照score进行排列;做排行榜应用,取top n 操作;(延迟任务,范围查找)
Redis的过期策略以及内存淘汰机制
redis采取的定期删除+惰性删除策略
定期删除需要一个定时器负责监视key,过期则自动删除,但是十分消耗CPU资源;
双层策略:定时:redis默认每个10ms检查,检查是否过期key,有则删除;检查为随机检查;惰性:当你获取某个key时,检查该key是否过期,有则删除;
若都没有删除,且内存更高,则采用内存淘汰机制:根据命令不同,分为几种:1.新写入操作报错;2.移除最少使用的key。推荐使用;3.随机移除key;4.在设置了过期时间的key中,移除最少使用的key(多用于把redis既当缓存,又做持久化的时候);
Redis数据库双写一致性问题:
强一致性要求 :不能放缓存;
最终一致性要求:只是降低不一致发生的概率;
首先,采取正确更新策略,先更新数据库,在删除缓存;期次,因为可能存在删除缓存失败的问题,提供一个补偿措施(利用消息队列)
缓存穿透:
缓存雪崩:
Redis的并发竞争key问题:
1.不要求顺序时:准备一个分布式锁,抢锁,然后做set操作;
2.要求顺序:在写入数据库的时候,保存一个时间戳;抢到锁后,比较时间戳,
利用队列,将set方法变成串行访问;