缓存穿透,缓存雪崩,缓存击穿

缓存穿透

问题:当访问一个不存在的商品id时因为没有缓存会直接查数据库,如果有高并发访问不存在的id可能导致数据库压力变大。

解决方法:可以把空值也进行缓存,但缓存时间可以相对较低

缓存雪崩

问题:如果大量商品的缓存是在同一时间生成的,比如每天零点跑脚本更新缓存,会导致1点时大量缓存同时过期,这时会出现大量数据库查询。

解决方法:可以将过期时间加上一些随机因子,比如过期时间随机设置为为45分钟至1小时15分。

缓存击穿

问题:缓存未生成或过期后,突然高并发访问。因为生成缓存需要一定的时间,所以在这段时间并发请求都认为缓存不存在都去查数据库。

解决方法1:设置不过期的缓存(在修改数据时再更新缓存)

解决方法2:在缓存的数据中也记录一个时间,但比缓存的过期时间短。比如缓存1小时,数据中记半个小时。半小时后再访问这条数据时仍然从缓存中返回数据,但是同时会往消息队列中发一条请求更新缓存的消息。然后后台任务消费消息时去更新缓存,在更新缓存前要再次检查时间,因为同一个商品并发访问时有可能发送多条消息,但是实际上去只需要更新一次缓存就够了,剩下的可以忽略。这里还涉及到消息分区的问题,因为一般会多线程消费消息队列,这时要保证同一个商品的更新请求不会出现在多个线程中。

方法2的方案更复杂,而且只能缓解击穿,不能避免,唯一的优势就是缓存会过期,能节省一部分缓存服务的使用空间。

InnoDB 聚集索引和非聚集索引

区别

聚集索引包含所需的所有数据,比如mysql整张表就是一个聚集索引
比如索引的key就是主键,值就是这一行的所有字段,根据主键查询时可以直接查到所有字段

非聚集索引不包含所有数据,但会包含聚集索引的key
比如索引的key是两个自定义的字段,而值就是主键,根据这两个字段,只能直接查出主键是什么,所以这时如果想查询其它字段的值还会通过主键去聚集索引中再查询一次(即回表)。

覆盖索引减少回表

如果查询的条件或结果中,只使用了非聚集索引定义中的那几个字段的话,就不会回表二次查询。
比如索引是uid, username两个字段:
执行SELECT status WHERE uid = ?时会回表二次查询status是什么
但执行SELECT username WHERE uid = ?时就不会二次查询,因为username在索引定义中。

如何创建聚集索引

聚集索引只是存储方式,不是索引类型,所以在创建索引时无法指定是否是聚集索引。

默认情况下会根据主键创建聚集索引。
如果没有主键,会根据第一个唯一索引创建聚集索引。
如果也没有唯一索引,会使用row id做聚集索引。

延伸:MyISAM

MyISAM中即使是聚集索引节点中也不包含数据,而是数据在硬盘的物理地址。而非聚集索引同样存的也是物理地址,所以没有回表问题。这么来看MyISAM好像比InnoDB快。但是因为MyISAM的节点上没有存储数据,所以数据在磁盘上有可能不是连续顺序存储的(按插入时间写入),那么在按范围查询的时候是不是会增加磁盘读取次数。

B树和B+树的区别

B树中的元素不会出现重复的,元素有可能在中间节点也有可能在叶子节点。
B+树中所有元素都会出现在叶子节点,但也有可能同时出现在中间节点。B+树叶子节点间有额外的链表结构。
这两点会让B+树在按连续的范围查找时比B树更快。
另外B树在查找时不同的元素因为在不同层级的节点,所以不同的元素查询时间可能有差异,而B+树所有的元素都在叶子节点所以查询的时间更平均一些

B树每个元素都包含卫星数据。
B+树只有叶子节点中的元素包含卫星数据。
这会使在中间节点的页大小相同的情况下B+树能比B树存更多的节点,也就意味着B+树有可能比B树更矮一些(树的高度决定磁盘io次数,越矮次数越少)

mysql查询字段中的条件判断

简单的值判断用CASE value WHEN compare_value THEN result ELSE result END

复杂的用IF(condition, true_result, false_result)

SELECT
	s.`id` AS '活动ID',
	s.`begin_date` AS '活动开始时间',
	s.`end_date` AS '活动结束时间',
	IF (s.`begin_date` > now() ,'未开始', IF(s.`end_date` < now() , '已结束' , '进行中' )) AS '状态',
	CASE s.`status` WHEN 1 THEN '已上线' ELSE '未上线' END AS '是否可用',
	sr.`product_id` AS '产品ID',
	sr.`sku_id` AS '库存ID'
FROM `activity_range` sr
LEFT JOIN `activity` s ON s.`id` = sr.`activity_id`

MySQL InnoDB配置优化

一、编译安装mysql(往后可以做)

二、增大内存(往后可以做,把192.168.8.150的16G内存换过来)

三、开启innodb的配置参数(现在必须做)

innodb_additional_mem_pool_size = 20M

innodb_buffer_pool_size = 2G

innodb_data_file_path = ibdata1:1024M:autoextend (这个暂时不设置,以后可以调整)

innodb_autoextend_increment = 256M

innodb_flush_log_at_trx_commit = 2

innodb_log_buffer_size = 16M

innodb_log_file_size = 256M

innodb_log_files_in_group = 3