查询缓存
工作原理:
缓存SELECT操作的结果集和SQL语句;
新的SELECT语句, 先去查询缓存, 判断是否存在可用的记录集;
判断标准:
与缓存的SQL语句, 是否完全一样, 区分大小写
(简单认为存储了一个key-value结构, key为sql, value为sql查询结果集)
query_cache_type
值: 0 -– 不启用查询缓存, 默认值;
值: 1 -– 启用查询缓存, 只要符合查询缓存的要求, 客户端的查询语句和记录集
都可以缓存起来, 供其他客户端使用, 加上 SQL_NO_CACHE将不缓存
值: 2 -– 启用查询缓存, 只要查询语句中添加了参数: SQL_CACHE, 且符合查询
缓存的要求, 客户端的查询语句和记录集, 则可以缓存起来, 供其他客户端使用(按需开启)
query_cache_size
允许设置query_cache_size的值最小为40K, 默认1M, 推荐设置 为: 64M/128M;
query_cache_limit
限制查询缓存区最大能缓存的查询记录集, 默认设置为1M
show status like 'Qcache%' 命令可查看缓存情况
查询不会缓存的情况:
1.当查询语句中有一些不确定的数据时, 则不会被缓存。 如包含函数NOW(),
CURRENT_DATE()等类似的函数, 或者用户自定义的函数, 存储函数, 用户变
量等都不会被缓存
2.当查询的结果大于query_cache_limit设置的值时, 结果不会被缓存
3.对于InnoDB引擎来说, 当一个语句在事务中修改了某个表, 那么在这个事务
提交之前, 所有与这个表相关的查询都无法被缓存。 因此长时间执行事务,
会大大降低缓存命中率
4, 查询的表是系统表
5, 查询语句不涉及到表
为什么mysql默认关闭了缓存开启?
1.在查询之前必须先检查是否命中缓存,浪费计算资源
2.如果这个查询可以被缓存, 那么执行完成后, MySQL发现查询缓存中没有这
个查询, 则会将结果存入查询缓存, 这会带来额外的系统消耗
3.针对表进行写入或更新数据时, 将对应表的所有缓存都设置失效。
4.如果查询缓存很大或者碎片很多时, 这个操作可能带来很大的系统消耗
适用场景:
以读为主的业务, 数据生成之后就不常改变的业务
比如门户类、 新闻类、 报表类、 论坛类等
查询优化处理的三个阶段
• 解析sql
通过lex词法分析,yacc语法分析将sql语句解析成解析树
https://www.ibm.com/developerworks/cn/linux/sdk/lex/
• 预处理阶段
根据mysql的语法的规则进一步检查解析树的合法性, 如: 检查数据的表
和列是否存在, 解析名字和别名的设置。 还会进行权限的验证
• 查询优化器
优化器的主要作用就是找到最优的执行计划
查询骑如何找到最优执行计划
1.使用等价变化规则 5 = 5 and a > 5 改写成 a > 5 a < b and a = 5 改写成 b > 5 and a = 5
2.外连接自动转为内连接
3.基于联合索引, 调整条件位置等
4. 优化count 、 min、 max等函数. min函数只需找索引最左边,max函数只需找索引最右边,myisam引擎count(*)
5. 覆盖索引扫描
6.子查询优化
7.提前终止查询 用了limit关键字或者使用不存在的条件
8.IN的优化 先进行排序, 再采用二分查找的方式
Mysql的查询优化器是基于成本计算的原则。 他会尝试各种执行计划。
数据抽样的方式进行试验( 随机的读取一个4K的数据块进行分析)
explian各个字段的含义
type
访问类型, sql查询优化中一个很重要的指标, 结果值从好到坏依次是:
system > const > eq_ref > ref > range > index > ALL
system: 表只有一行记录( 等于系统表) , const类型的特例, 基本不会出现, 可以忽略不计
const: 表示通过索引一次就找到了, const用于比较primary key 或者 unique索引
eq_ref: 唯一索引扫描, 对于每个索引键, 表中只有一条记录与之匹配。 常见于主键 或 唯一索引扫描
ref: 非唯一性索引扫描, 返回匹配某个单独值的所有行, 本质是也是一种索引访问
range: 只检索给定范围的行, 使用一个索引来选择行
index: Full Index Scan, 索引全表扫描, 把索引从头到尾扫一遍
ALL: Full Table Scan, 遍历全表以找到匹配的行
possible_keys
查询过程中有可能用到的索引
key
实际使用的索引, 如果为NULL, 则没有使用索引
rows
根据表统计信息或者索引选用情况, 大致估算出找到所需的记录所需要读取的行
数
filtered
它指返回结果的行占需要读到的行(rows列的值)的百分比
表示返回结果的行数占需读取行数的百分比, filtered的值越大越好
Extra
1、 Using filesort :
mysql对数据使用一个外部的文件内容进行了排序, 而不是按照表内的索引进行排序读取
2、 Using temporary:
使用临时表保存中间结果, 也就是说mysql在对查询结果排序时使用了临时表, 常见于order by 或 group by
3、 Using index:
表示相应的select操作中使用了覆盖索引( Covering Index) , 避免了访问表的数据行, 效率高
4、 Using where :
使用了where过滤条件
5、 select tables optimized away:
基于索引优化MIN/MAX操作或者MyISAM存储引擎优化COUNT(*)操作, 不必等到执行阶段在进行计算, 查询执行计划生成的阶段即可完成优化
慢查询日志的使用
配置
show variables like 'slow_query_log'
set global slow_query_log = on
set global slow_query_log_file = '/var/lib/mysql/gupaoedu-slow.log'
set global log_queries_not_using_indexes = on
set global long_query_time = 0.1 (秒)
日志分析
Time : 日志记录的时间
User@Host: 执行的用户及主机
Query_time: 查询耗费时间 Lock_time 锁表时间 Rows_sent 发送给请求方的记录
条数 Rows_examined 语句扫描的记录条数
SET timestamp 语句执行的时间点
select .... 执行的具体语句
分析工具
mysqldumpslow -t 10 -s at /var/lib/mysql/gupaoedu-slow.log
InnoDB的锁
一.锁的类型
共享锁:
又称为读锁, 简称S锁, 顾名思义, 共享锁就是多个事务对于同一数据可以共享一把锁,
都能访问到数据, 但是只能读不能修改;
加锁释锁方式:
select * from users WHERE id=1 LOCK IN SHARE MODE;
commit/rollback
排他锁:
又称为写锁, 简称X锁, 排他锁不能与其他锁并存, 如一个事务获取了一个数据行的排他
锁, 其他事务就不能再获取该行的锁( 共享锁、 排他锁) , 只有该获取了排他锁的事务是可以对
数据行进行读取和修改, ( 其他事务要读取数据可来自于快照)
加锁释锁方式:
delete / update / insert 默认加上X锁
SELECT * FROM table_name WHERE ... FOR UPDATE
commit/rollback
意向共享锁(IS):
表示事务准备给数据行加入共享锁, 即一个数据行加共享锁前必须先取得该表的IS锁,
意向共享锁之间是可以相互兼容的
意向排它锁(IX):
表示事务准备给数据行加入排他锁, 即一个数据行加排他锁前必须先取得该表的IX锁,
意向排它锁之间是可以相互兼容的
意向锁(IS、 IX)是InnoDB数据操作之前自动加的, 不需要用户干预
意义:当事务想去进行锁表时, 可以先判断意向锁是否存在, 存在时则可快速返回该表不能
启用表锁
理解:意向锁相当于一个判断锁是否被锁定过的flag
自增锁(AUTO-INC Locks)
针对自增列自增长的一个特殊的表级别锁
show variables like 'innodb_autoinc_lock_mode';
默认取值1, 代表连续, 事务未提交ID永久丢失
临间锁(Next-key locks):
锁住记录+区间(左开右闭)
当sql执行按照索引进行数据的检索时,查询条件为范围查找( between and、 <、 >等) 并有数
据命中则此时SQL语句加上的锁为Next-key locks, 锁住索引的记录+区间( 左开右闭)
防止幻读
间隙锁(Gap Locks)
当sql执行按照索引进行数据的检索时, 查询条件的数据不存在, 这时SQL语句加上的锁即为
Gap locks, 锁住索引不存在的区间( 左开右开)
Record locks:
锁住具体的索引项
当sql执行按照唯一性( Primary key、 Unique key) 索引进行数据的检索时, 查询条件等值匹配且查询的数据是存在, 这时SQL语句加上的锁即为记录锁Record locks, 锁住具体的索引项
二、利用锁类解决脏读、不可重复读、幻读
三、InnoDB行锁到底锁了什么
InnoDB的行锁是通过给索引上的索引项加锁来实现的。
只有通过索引条件进行数据检索,InnoDB才使用行级锁,否则,InnoDB将使用表锁(锁住索引的所有记录)
表锁:lock tables xx read/write
四、死锁
1)类似的业务逻辑以固定的顺序访问表和行。
2)大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小。
3)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概
率。
4)降低隔离级别,如果业务允许,将隔离级别调低也是较好的选择
5)为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添
加上锁(或者说是表锁)