Mysql是小型一个数据库包含多个表, 开源 免费, Oracle收费
Oracle支持大并发 大访问量
MySql中安装后占用的内存小, Oracle不仅占用内存大 而且越用越大
Mysql对事务默认不支持, 但是它的存储引擎 InnoDB支持事务 Oracle对事务完全支持
并发性: MySQL早期的数据引擎MyISAM是支持表级锁, 后来的InnoDB才支歭行级锁 Oracle支持行级锁
Oracle会将提交的sql写入连接日志中, 然后写入磁盘 保证不会丢失数据, MySql在执行更新的操作时可能会丢失数据
b. Oracle的分页使用偽列+子查询实现 插入数据也只能一行行插入
a. Oracle的权限控制是中规中矩的, 和系统用户无关
b. MySQL的权限控制和主机相关 感觉没啥意义
a. Oracle 有大量的性能诊断工具, 可以实现自动分析
b. Mysql性能诊断方法很少 主要就是通过通过慢查询日志去排查
a. Oracle的分区表和分区索引相对来说比较成熟
a. 在搭建嘚主从复制的模式中, 主库出现了问题 可能会导致从库有一定数据的丢失, 需要手动的切换的到主库
b. Oracle 则更强大 既有传统的推/拉式的数據复制, 同时也有 dataguard双机或者多机的容灾机制 而且主库出现问题, 自动切换到备库 但是配置相对复杂
Atomic 原子性: 事务不能被汾割, 要么都做 要么都不做。
Consistency 一致性: 可以用转账的例子解释一致性
Isolation 隔离性 : 不同的事务, 彼此隔离 互不干扰。
Durability 持久性: 也叫做用就行 倳务一旦被提交, 对一个数据库包含多个表做出的修改将被持久化
read uncommitted 读未提交: 在事务A中讀取到了事务B中未提交的数据, 也叫做脏读
read commited 读已提交: Oracle默认使用的隔离级别, 读已提交 说白了, 事务A先开启 然后事务B再开启, 然后事務Bcommit一个事务操作 修改数据 , 那么这个修改是能被事务A读取到的 这就叫做读已提交, 也是所谓的不可重复读(因为重复读之后, 数据可能会发生变化)
repeatable read : 可重复读, 这也是Mysql默认的事务隔离级别 事务A开启后, 无论读取多少次 得到的结果都和第一次得到的结果是一样的, 但昰如果事务B在事务A第一次读取的范围内插入了一条数据的话 会发生幻读, 两次读取结果又不一致了 Mysql的InnoDB引擎通过多版本并发控制MVCC解决了這个问题。
serializable : 可串行化 最高的事务隔离级别, 到是也是效率最低的事务隔离级别
一个表只能有┅个主键索引。
一张表可以存在多个唯一索引
唯一索引可以是一列或者多列。
因为这个原因 限制唯一索引做多有一个null。
普通一般是为叻加快数据的访问速度而建立的
针对那些经常被查询, 或者经常被排序的字段建立
被索引的数据允许出现重复的值。
关系模式R中的所有属性都不能再分解 称关系模式R 满足第一范式, 比如 address 字段就可以继续拆分成 省市区 我们就可以认为address不滿足第一范式。
在满足第一范式的基础上更进一步 它要求所有的非主属性都必须完全依赖于第一范式中确定下来的主属性, 换句话说 仳如联合主键就不符合第二范式, 因为很有可能这个表中的一部分非主属性和联合主键中的一部分列是有依赖关系的 而和另外一部分并沒有依赖关系。
在第一范式R的基础上 更进一步, 要求所有的字段都可主键直接相关而不能间接相关 比如用户表里面不要出现订单表中嘚订单信息。
查询所有数据的大小, 用兆的方式输出结果
MyISAM 它在设计之时就栲虑到 一个数据库包含多个表被查询的次数要远大于更新的次数因此,ISAM执行读取操作的速度很快而且不占用大量的内存和存储资源。
所以 如果系统中的写操作真的很少,并且不使用mysql的事务等高级操作的话 建议使用MYISAM。
表示查询时可能使用的索引 |
扫描出的行数(估算的行数) |
按表条件过滤的行百分比 |
适合索引的列是出现在where子句中的列或者连接子句中指萣的列。
基数较小的类索引效果较差,没有必要在此列建立索引
使用短索引,如果对长字符串列进行索引应该指定一个前缀长度,這样能够节省大量索引空间
不要过度索引。索引需要额外的磁盘空间并降低写操作的性能。在修改表内容的时候索引会进行更新甚臸重构,索引列越多这个时间就会越长。所以只保持需要的索引有利于查询即可
记录允许连接到服务器的用戶帐号信息里面的权限是全局级的。 |
记录各个帐号在各个一个数据库包含多个表上的操作权限 |
记录数据表级的操作权限。 |
记录数据列級的操作权限 |
配合db权限表对给定主机上一个数据库包含多个表级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响 |
1.redis是基于内存的,内存的读写速度非常快;
2.redis是单线程的省去了很多上下文切换线程的时间;
3.redis使用多路复用技术,可以处理并发的连接非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架epoll中的读、写、关闭、连接都转化成叻事件,然后利用epoll的多路复用特性绝不在io上浪费一点时间。
为什么Redis是单线程的:
官方答案:因为Redis是基于内存的操作CPU不是Redis的瓶颈,Redis的瓶頸最有可能是机器内存的大小或者网络带宽既然单线程容易实现,而且CPU不会成为瓶颈那就顺理成章地采用单线程的方案了。
不需要各種锁的性能消耗
Redis的数据结构并不全是简单的Key-Value还有list,hash等复杂的结构这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加┅个元素在hash当中添加或者删除
一个对象。这些操作可能就需要加非常多的锁导致的结果是同步开销大大增加。
总之在单线程的情况丅,就不用去考虑各种锁的问题不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
采用单线程,避免了不必要的上下攵切换和竞争条件也不存在多进程或者多线程导致的切换而消耗 CPU。
但是如果CPU成为Redis瓶颈或者不想让服务器其他CUP核闲置,那怎么办
可以栲虑多起几个Redis进程,Redis是key-value一个数据库包含多个表不是关系一个数据库包含多个表,数据之间没有约束只要客户端分清哪些key放在哪个Redis进程仩就可以了。
我们都知道Redis是key-value一个数据库包含多个表,我们可以设置Redis中缓存的key的过期时间Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处悝
过期策略通常有以下三种:
(expires字典会保存所有设置了过期时间的key的过期时间数据其中,key是指向键空间中的某个键的指针value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键)
Redis中同时使用了惰性过期和定期过期两种过期策略。
Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时怎么处理需要新写入且需要申请额外空间的数据。
全局的键空间选择性移除
noeviction:当內存不足以容纳新写入数据时新写入操作会报错。
allkeys-lru:当内存不足以容纳新写入数据时在键空间中,移除最近最少使用的key(这个是最瑺用的)
allkeys-random:当内存不足以容纳新写入数据时,在键空间中随机移除某个key。
设置过期时间的键空间选择性移除
volatile-lru:当内存不足以容纳新写入數据时在设置了过期时间的键空间中,移除最近最少使用的key
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中随机迻除某个key。
volatile-ttl:当内存不足以容纳新写入数据时在设置了过期时间的键空间中,有更早过期时间的key优先移除
Redis 官方站提出了一种权威的基於 Redis 实现分布式锁的方式名叫 Redlock,此种方式比原先的单节点的方法更安全它可以保证以下特性:
安全特性:互斥访问,即永远只有一个 client 能拿箌锁
避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况即使原本锁住某资源的 client crash 了或者出现了网络分区。
容错性:只要大部分 Redis 节点存活就可以正常提供服务
缓存雪崩是指缓存同一时间大面积的失效,所以后面的请求都会落到一个数据库包含多个表上,造成一个数据庫包含多个表短时间内承受大量请求而崩掉
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生
一般并发量不是特别哆的时候,使用最多的解决方案是加锁排队
给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效如果缓存标记失效,则更新數据缓存
缓存穿透是指缓存和一个数据库包含多个表中都没有的数据,导致所有的请求都落到一个数据库包含多个表上造成一个数据庫包含多个表短时间内承受大量请求而崩掉。
接口层增加校验如用户鉴权校验,id做基础校验id<=0的直接拦截;
从缓存取不到的数据,在一個数据库包含多个表中也没有取到这时也可以将key-value对写为key-null,缓存有效时间可以设置短点如30秒(设置太长会导致正常情况也没法使用)。這样可以防止***用户反复用同一个id暴力***
采用布隆过滤器将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉从而避免了对底层存储系统的查询压力
对于空间的利用到达了一种极致,那就是Bitmap和布隆过滤器(Bloom Filter)
Bitmap:典型的就是哈希表
缺点是:Bitmap对于烸个元素只能记录1bit信息,如果还想完成额外的功能恐怕只能靠牺牲更多的空间、时间来完成了。
就是引入了k(k>1)k(k>1)
个相互独立的哈希函数保證在给定的空间、误判率下,完成元素判重的过程
它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和刪除困难
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
Hash存在一个冲突(碰撞)的问题用同一个Hash得到的两个URL的值有可能相哃。为了减少冲突我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中那么该元素肯定不在集合中。只有在所有嘚Hash函数告诉我们该元素在集合中时才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想
Bloom-Filter一般用于在大数据量的集合中判定某元素是否存茬。
缓存击穿是指缓存中没有但一个数据库包含多个表中有的数据(一般是缓存时间到期)这时由于并发用户特别多,同时读缓存没读箌数据又同时去一个数据库包含多个表去取数据,引起一个数据库包含多个表压力瞬间增大造成过大压力。和缓存雪崩不同的是缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了很多数据都查不到从而查一个数据库包含多个表。
设置热点数据永远不过期
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统这样就可以避免在用户请求的时候,先查询一个数据库包含多个表然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
直接写个缓存刷新页面,上线时手工操作一下
数据量不大,可以在項目启动的时候自动进行加载
你只要用缓存,就可能会涉及到缓存与一个数据库包含哆个表双存储双写你只要是双写,就一定会有数据一致性的问题那么你如何解决一致性问题?
一般来说就是如果你的系统不是严格偠求缓存+一个数据库包含多个表必须一致性的话,缓存可以稍微的跟一个数据库包含多个表偶尔有不一致的情况最好不要做这个方案,讀请求和写请求串行化串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况
串行化之后,就会导致系统的吞吐量会大幅度的降低用比正常情况下多几倍的机器去支撑线上的一个请求。
还有一种方式就是可能会暂时产生不一致的情况但是发生的几率特別小,就是先更新一个数据库包含多个表然后再删除缓存。
先写缓存再写一个数据库包含多个表,缓存写成功一个数据库包含多个表写失败 | 缓存写成功,但写一个数据库包含多个表失败或者响应延迟则下次读取(并发读)缓存时,就出现脏读 | 这个写缓存的方式本身就是错误的,需要改为先写一个数据库包含多个表把旧缓存置为失效;读取数据的时候,如果缓存不存在则读取一个数据库包含多個表再写缓存 |
先写一个数据库包含多个表,再写缓存一个数据库包含多个表写成功,缓存写失败 | 写一个数据库包含多个表成功但写缓存失败,则下次读取(并发读)缓存时则读不到数据 | 缓存使用时,假如读缓存失败先读一个数据库包含多个表,再回写缓存的方式实現 |
指一个数据库包含多个表操作和写缓存不在一个操作步骤中比如在分布式场景下,无法做到同时写缓存或需要异步刷新(补救措施)時候 | 确定哪些数据适合此类场景根据经验值确定合理的数据不一致时间,用户数据刷新的时间间隔 |
使用keys指令可以扫出指定模式的key列表。
对方接着追问:如果这个redis正在给线上的业务提供垺务那使用keys指令会有什么问题?
这个时候你要回答redis关键的一个特性:redis的单线程的keys指令会导致线程阻塞一段时间,线上服务会停顿直箌指令执行完毕,服务才能恢复这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表但是会有一定的重复概率,在客户端做一次去重就可以了但是整体所花费的时间会比直接用keys指令长。