mysql高级

github笔记
csdn笔记

select 输出的列名 from 表名 where 条件 group by 分组条件 having 分组之后的条件过滤 order by 排序的列名 asc|desc limit 起始索引,显示几条

mysql高级_第1张图片
怎么学好Mysql?学什么?怎么学?

一、 linux

var 目录,变量配置文件
var/lib/mysql/ mysql数据库文件的存放路径
没有提示即可
rpm -qa|grep -i mysql 查看是否安装mysql 。
rpm -ivh mysql.rpm 查看安装进度
chkconfig mysql on 设置开机自启动
ntsysv 查看开机启动项(*为开机启动项)
top 查看开机时间

二、B+树

叶子节点有指针(顺序),叶子节点包含所有的元素,一个节点里面可以有多个元素
(B+树只有叶子节点才存储数据)

  • B-树(B树):多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
    叶子节点具有相同的深度,叶子节点的指针为空
    所有索引元素不重复
    节点中的数据索引从左到右递增排列

  • B+树(多叉平衡树):在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
    非叶子节点不存储数据,只存储索引

  • B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3;

为什么使用B Tree(B+Tree)
红黑树(二叉平衡树)也可用来实现索引,但是文件系统及数据库系统普遍采用B/+Tree,为什么?

二叉树不适合数据单边增长情况,退化成链表
红黑树在数据量大时,树的高度不可控
一般来说,索引本身也很大,不可能全存内存,往往以索引文件的形式存在磁盘
  (1)单节点能存储更多数据,使得磁盘IO次数更少。
  (2)叶子节点形成有序链表,便于执行范围操作。
  (3)聚集索引中,叶子节点的data直接包含数据;非聚集索引中,叶子节点存储数据地址的指针。

数据库表的InnoDB存储引擎插入时会按主键排序,提高查询效率
explain + sql语句,查看是否使用索引。性能分析
字段操作(包括类型转换),不使用索引。where a=‘a’(a建立索引,int类型。类型转换后相当于a=0,数字字符可转换为对应数字,其它字符只能转换为0)
mysql高级_第2张图片淘宝使用 OceanBase 企业级分布式数据库

三、mysql分层

插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储相分离
1.连接层
2.服务层
3.引擎层
4.存储层
myISM索引文件和数据文件是分离的(非聚集索引)
mysql高级_第3张图片
没有建主键时,MySQL会维护一个隐藏列的数据结构,来保证唯一性.MySQL本身资源紧张,效率不高.主键将帮助用户在迁移数据时,不会引入重复数据问题所以必须建主键
innoDB支持事务,外键,行锁,缓存(不仅缓存索引,也缓存真实数据,对内存要求较高,而且内存大小对性能有决定性影响),表空间大,关注点事务
myISM,表锁(不适合高并发),缓存(只缓存索引,不缓存真实数据),表空间小,关注点性能(偏重读)

对比项 MyISAM InnoDB
主外键 不支持 支持
事务 不支持 支持
行表锁 表锁,即使操作一条记录也会锁住整张表,不适合高并发操作 行锁,操作时只锁某一行,不对其他行有影响,适合高并发操作
缓存 只缓存索引,不缓存真实数据 不仅缓存索引还要缓存真实数据,対内存要求较高,而且内存大小対性能有决定性影响
表空间
关注点 性能 事务
默认安装 Y Y
  • 主键使用
    1、不更新主键列的值
    2、不重用主键列的值
    3、不在主键列中使用可能会更改的值(例如,如果使用一个名字作为主键以标识某个供应商,应该供应商合并和更改其名字时,必须更改这个主键)

1.SQL性能下降的原因

查询语句写的差。
索引失效:索引建了,但是没有用上。
关联 查询太多join(设计缺陷或者不得已的需求)。
服务器调优以及各个参数的设置(缓冲、线程数等)。

2.SQL执行顺序

select # 5

from # 1

where # 2

group by # 3

having # 4

order by # 6

limit # 7
[offset]

四、查询

mysql高级_第4张图片
mysql高级_第5张图片
oracle的full outer join
SELECT FROM TableA A LEFT JOIN TableB B ON A.Key = B.Key
UNION
SELECT FROM TableA A RIGHT JOIN TableB B ON A.Key = B.Key;

五、索引

MySQL官方对索引的定义为:索引(INDEX)是帮助MySQL高效获取数据的数据结构。
从而可以获得索引的本质:索引是排好序的快速查找数据结构(where,order by)
300万以上一般需要索引

查找和排序

范围索引会使联合索引失效
复合索引的最左前缀原则,跳过最左的索引,将不使用索引

5.1 索引数据结构:

mysql高级_第6张图片

  • BTree索引。
  • Hash索引。
    mysql高级_第7张图片
  • Full-text全文索引。
  • R-Tree索引。

5.2.哪些情况需要建索引

  • 主键自动建立主键索引(唯一 + 非空)。
  • 频繁作为查询条件的字段应该创建索引。
  • 查询中与其他表关联的字段,外键关系建立索引。
  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。(order by字段顺序很重要)
  • 查询中统计或者分组字段(group by也和索引有关)。

高并发下倾向组合索引

5.3 哪些情况不要建索引

  • 记录太少的表。

  • 经常增删改的表。

  • 频繁更新的字段不适合创建索引。

  • Where条件里用不到的字段不创建索引。

  • 数据重复且分布平均的表字段,应该只为最经常查询和排序的字段建立索引。(如果某个数据列包含许多重复的内容,为它建立索引就没有太大效果)
    假如一个表有10万行记录,有一个字段A只有true和false两种值,并且每个值的分布概率大约为50%,那么对A字段建索引一般不会提高数据库的查询速度。索引的选择性是指索引列中不同值的数目与表中记录数的比。如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000=0.99。一个索引的选择性越接近于1,这个索引的效率就越高。

5.4、聚集索引和非聚集索引

聚集索引和非聚集索引使用的都是B+树结构。

1、非聚集索引
非聚集索引的叶子节点为索引节点,但是有一个指针指向数据节点。

MyISAM是非聚集索引。

2、聚集索引
聚集索引叶子节点就是数据节点。

关于聚集索引,innodb会按照如下规则进行处理:
  1,如果一个主键被定义了,那么这个主键就是作为聚集索引
  2,如果没有主键被定义,那么该表的第一个唯一非空索引被作为聚集索引
  3,如果没有主键也没有合适的唯一索引,那么innodb内部会生成一个隐藏的主键作为聚集索引,这个隐藏的主键是一个6个字节的列,该列的值会随着数据的插入自增。

innodb的普通索引,唯一索引,联合索引都是辅助索引,采用非聚集索引结构。InnoDB的所有辅助索引都引用主键作为data域。

聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

六、性能分析

mysql常见瓶颈
cpu,io,服务器硬件(top,free,iostat,vmstat查看)

6.1.EXPLAIN能干嘛?

可以查看以下信息:

  • id:表的读取顺序。
  • select_type:数据读取操作的操作类型。
  • possible_keys:哪些索引可以使用。
  • key:哪些索引被实际使用。
  • ref:表之间的引用。
  • rows:每张表有多少行被优化器查询。越小越好

id,type,key,rows,extra最重要
\G,竖版显示

6.2.EXPLAIN字段

id 加载顺序

id:表的读取和加载顺序。

值有以下三种情况:
id相同,执行顺序由上至下。
id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行。
id相同不同,同时存在。永远是id大的优先级最高,id相等的时候顺序执行。

select_type 查询类型

  • SIMPLE:简单的SELECT查询,查询中不包含子查询或者UNION 。
  • PRIMARY:查询中如果包含任何复杂的子部分,最外层查询则被标记为PRIMARY。
  • SUBQUERY:在SELECT或者WHERE子句中包含了子查询。
  • DERIVED:在FROM子句中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中。
  • UNION:如果第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为DERIVED。
  • UNION RESULT:从UNION表获取结果的SELECT。

type

type:访问类型排列。索引级别

从最好到最差依次是:system>const>eq_ref>ref>range>index>ALL。除了ALL没有用到索引,其他级别都用到索引了。
(system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>All)
一般来说,得保证查询至少达到range级别,最好达到ref。

  • const:表示通过索引一次就找到了,const用于比较primary key或则unique索引。单表
  • eq_ref:联表。const是通过索引一次就找到唯一一条数据.eq是连表查找,(…对于每个索引键…),说明访问的就不止一个索引列,需要访问多个索引,但是值还是唯一的.相同点是值唯一,不同点是访问的索引列数量不同. const只有一条记录,eq-ref是可能多条,但是A表的外健对应B表中只有一条记录
  • index:Full Index Scan,全索引扫描,index和ALL的区别为index类型只遍历索引树。也就是说虽然ALL和index都是读全表,但是index是从索引中读的,ALL是从磁盘中读取的。
  • ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。查询中与其它表关联的字段,外键关系建立索引。

Extra

Extra:包含不适合在其他列中显示但十分重要的额外信息。
最重要的字段:Using filesort(较差),Using temporary(很差),using index(好)

  • Using filesort:说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作成为"文件内排序"。
    (order by字段要和 组合索引 中的字段和顺序相同,否则 )
  • Using temporary:使用了临时表保存中间结果,MySQL在対查询结果排序时使用了临时表。常见于排序order by和分组查询group by。临时表対系统性能损耗很大。(where…in与group by字段要和 组合索引 中的字段和顺序相同,否则 )
  • Using index:表示相应的select操作中使用了覆盖索引(Covering Index),避免了访问表的数据行,效率不错!如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找动作
  • null: key列有用到索引的时候,表示没有用到索引覆盖,使用了回表查询,性能比覆盖索引差

七、索引失效

  1. 单表索引优化:
    建立复合索引时,范围参数不建索引,否则索引会失效
  2. 索引两表优化:
    左连接时,索引建在右表。右连接,建左表
  3. 索引三表优化:
    从表建立索引

1.JOIN语句的优化:

  • 尽可能减少JOIN语句中的NestedLoop(嵌套循环)的总次数:永远都是小的结果集驱动大的结果集。
  • 优先优化NestedLoop的内层循环。
  • 保证JOIN语句中被驱动表上JOIN条件字段已经被索引。
  • 当无法保证被驱动表的JOIN条件字段被索引且内存资源充足的前提下,不要太吝惜Join Buffer 的设置。

2.题目

/* 创建复合索引 */
CREATE INDEX idx_test03_c1234 ON `test03`(`c1`,`c2`,`c3`,`c4`);

/* 1.用到索引c1 c2 c3 c4全字段 MySQL的查询优化器会优化SQL语句的顺序*/
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c2` = 'a2' AND `c4` > 'a4' AND `c3` = 'a3';
/* 2.用到了索引c1 c2 c3三个字段,c1和c2两个字段用于查找, c3字段用于排序了但是没有统计到key_len中*/
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c2` = 'a2' ORDER BY `c3`;
  /* 3.用到了索引c1 c2 c3三个字段, c1和c2两个字段用于查找,  c3字段用于排序了但是没有统计到key_len中,c4字段失效
*/
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c2` = 'a2' AND `c4` = 'a4' ORDER BY `c3`;
/* 
   4.用到了索引c1 c2两个字段,c4失效,c1和c2两个字段用于查找,c4字段排序产生了Using filesort说明排序没有用到c4字段 
*/
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c2` = 'a2' ORDER BY `c4`;
/* 5.1 用到了索引c1 c2 c3三个字段,c1用于查找,c2和c3用于排序.没有出现filesort */
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c5` = 'a5' ORDER BY `c2`, `c3`;
/* 5.2.用到了c1一个字段,c1用于查找,c3和c2两个字段索引失效,产生了Using filesort */
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c5` = 'a5' ORDER BY `c3`, `c2`;
/* 
   5.3. 用到了c1 c2 c3三个字段,c1 c2用于查找,c2 c3用于排序 没有产生Using filesort 
      因为之前c2这个字段已经确定了是'a2'了,这是一个常量,再去ORDER BY c3,c2 这时候c2已经不用排序了!
      所以没有产生Using filesort .和(5.2)进行对比学习!
*/
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c2` = 'a2' AND `c5` = 'a5' ORDER BY c3, c2;


/* GROUP BY 表面上是叫做分组,但是分组之前必定排序。 */

/* 14.用到c1 c2 c3三个字段,c1用于查找,c2 c3用于排序,c4失效 */
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c4` = 'a4' GROUP BY `c2`,`c3`;

/* 15.用到c1这一个字段,c4失效,c2和c3排序失效产生了Using temporary;Using filesort,性能下降厉害 */
EXPLAIN SELECT * FROM `test03` WHERE `c1` = 'a1' AND `c4` = 'a4' GROUP BY `c3`,`c2`;
  • 定值、范围还是排序,一般order by是给个范围
  • group by基本上都需要进行排序,顺序不对会有临时表产生

3.索引优化的一般性建议:

  • 对于单值索引,尽量选择针对当前query过滤性更好的索引。
  • 在选择复合索引的时候,当前query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。
  • 在选择复合索引的时候,尽量选择能够包含当前query中的where子句中更多字段的索引。
  • 尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的。

利用覆盖索引解决两边%的优化问题,同时不写星

kk%,前面是定值,可以用到索引,不影响后面字段
%kk,使用不到索引

优化总结口诀:
全值匹配我最爱(无关顺序),最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写星;
不等空值还有or,索引失效要少用;
VARCHAR引号不可丢,SQL高级也不难!

八、分析慢SQL的步骤

  • 分析:

1、观察,至少跑1天,看看生产的慢SQL情况。
2、开启慢查询日志,设置阈值,比如超过5秒钟的就是慢SQL,并将它抓取出来。
3、explain + 慢SQL分析。
4、show Profile。
5、运维经理 OR DBA,进行MySQL数据库服务器的参数调优。

  • 总结(大纲):

1、慢查询的开启并捕获。
2、explain + 慢SQL分析。
3、show Profile查询SQL在MySQL数据库中的执行细节和生命周期情况。
4、MySQL数据库服务器的参数调优。

九、查询优化

1.小表驱动大表

优化原则:对于MySQL数据库而言,永远都是小表驱动大表。

/**
* 举个例子:可以使用嵌套的for循环来理解小表驱动大表。
* 以下两个循环结果都是一样的,但是对于MySQL来说不一样,
* 第一种可以理解为,和MySQL建立5次连接每次查询1000次。
* 第一种可以理解为,和MySQL建立1000次连接每次查询5次。
*/
for(int i = 1; i <= 5; i ++){
    for(int j = 1; j <= 1000; j++){
        
    }
}
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
for(int i = 1; i <= 1000; i ++){
    for(int j = 1; j <= 5; j++){
        
    }
}

IN和EXISTS

/* IN适合B表比A表数据小的情况*/
SELECT * FROM A WHERE id IN (SELECT id FROM B)

/* EXISTS适合B表比A表数据大的情况 */
SELECT * FROM A WHERE EXISTS (SELECT 1 FROM B WHERE B.id = A.id);
EXISTS:

语法:SELECT…FROM tab WHERE EXISTS(subquery);该语法可以理解为:
该语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(true或是false)来决定主查询的数据结果是否得以保留。
提示:

EXISTS(subquery)子查询只返回true或者false,因此子查询中的SELECT *可以是SELECT 1 OR SELECT X,它们并没有区别。
EXISTS(subquery)子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比,如果担心效率问题,可进行实际检验以确定是否有效率问题。
EXISTS(subquery)子查询往往也可以用条件表达式,其他子查询或者JOIN替代,何种最优需要具体问题具体分析。

2.order by优化

ORDER BY子句,尽量使用索引排序,避免使用Using filesort排序。

MySQL支持两种方式的排序,FileSortIndexIndex的效率高,它指MySQL扫描索引本身完成排序。FileSort方式效率较低。

ORDER BY满足两情况,会使用Index方式排序:

  • ORDER BY语句使用索引最左前缀。
  • 使用WHERE子句与ORDER BY子句条件列组合满足索引最左前缀。

结论:尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀原则。

如果不在索引列上,File Sort有两种算法:MySQL就要启动双路排序算法和单路排序算法

1、双路排序算法:MySQL4.1之前使用双路排序,字面意思就是两次扫描磁盘,最终得到数据,读取行指针和ORDER BY列,対他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出。一句话,从磁盘取排序字段,在buffer中进行排序,再从磁盘取其他字段。

取一批数据,要对磁盘进行两次扫描,众所周知,IO是很耗时的,所以在MySQL4.1之后,出现了改进的算法,就是单路排序算法。

2、单路排序算法:从磁盘读取查询需要的所有列,按照ORDER BY列在buffer対它们进行排序,然后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据。并且把随机IO变成了顺序IO,但是它会使用更多的空间,因为它把每一行都保存在内存中了。

由于单路排序算法是后出的,总体而言效率好过双路排序算法。

但是单路排序算法有问题:如果SortBuffer缓冲区太小,导致从磁盘中读取所有的列不能完全保存在SortBuffer缓冲区中,这时候单路复用算法就会出现问题,反而性能不如双路复用算法。

单路复用算法的优化策略:

  • 增大sort_buffer_size参数的设置。
  • 增大max_length_for_sort_data参数的设置。

提高ORDER BY排序的速度:

  • ORDER BY时使用SELECT *是大忌,查什么字段就写什么字段,这点非常重要。在这里的影响是:

    • 当查询的字段大小总和小于max_length_for_sort_data而且排序字段不是TEXT|BLOB类型时,会使用单路排序算法,否则使用多路排序算法。
    • 两种排序算法的数据都有可能超出sort_buffer缓冲区的容量,超出之后,会创建tmp临时文件进行合并排序,导致多次IO,但是单路排序算法的风险会更大一些,所以要增大sort_buffer_size参数的设置。
  • 尝试提高sort_buffer_size:不管使用哪种算法,提高这个参数都会提高效率,当然,要根据系统的能力去提高,因为这个参数是针对每个进程的。

  • 尝试提高max_length_for_sort_data:提高这个参数,会增加用单路排序算法的概率。但是如果设置的太高,数据总容量sort_buffer_size的概率就增大,明显症状是高的磁盘IO活动和低的处理器使用率。

3.GORUP BY优化

  • GROUP BY实质是先排序后进行分组,遵照索引建的最佳左前缀。

  • 当无法使用索引列时,会使用Using filesort进行排序,增大max_length_for_sort_data参数的设置和增大sort_buffer_size参数的设置,会提高性能。

  • WHERE执行顺序高于HAVING,能写在WHERE限定条件里的就不要写在HAVING中了。

4.总结

为排序使用索引

  • MySQL两种排序方式:Using filesortIndex扫描有序索引排序。
  • MySQL能为排序与查询使用相同的索引,创建的索引既可以用于排序也可以用于查询。

十、慢查询日志

10.1 查看慢查询日志是否开以及如何开启

  1. 查看慢查询日志是否开启:SHOW VARIABLES LIKE ‘%slow_query_log%’;。

开启慢查询日志:SET GLOBAL slow_query_log = 1;。使用该方法开启MySQL的慢查询日志只对当前数据库生效,如果MySQL重启后会失效。

  1. 查看当前多少秒算慢:SHOW VARIABLES LIKE ‘long_query_time%’;
  • 设置慢的阈值时间:set global long_query_time=3;

  • 为什么设置后看不出变化(设置3之后,查询依然显示10):
    show global variables like ‘long_query_time’;

需要重新连接或新开一个会话才能看到修改值。
SHOW VARIABLES LIKE ‘long_query_time%’;

  • 查询当前系统中有多少条慢查询记录:

show global status like ‘%Slow_queries%’;
3. 配置版
mysql高级_第8张图片

10.2 日志分析工具mysqldumpslow

如何在windows下使用mysqldumpslow命令

11. Show Profile

Show Profile是什么?

Show Profile:MySQL提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于SQL的调优的测量。默认情况下,参数处于关闭状态,并保存最近15次的运行结果。

查看Show Profile功能是否开启
mysql> SHOW VARIABLES LIKE ‘profiling’;

开启Show Profile功能,默认是关闭的,使用前需要开启
mysql> SET profiling=ON;

查看结果,执行SHOW PROFILES;

诊断SQL,SHOW PROFILE cpu,block io FOR QUERY Query_ID;

Show Profile查询参数备注:

  • ALL:显示所有的开销信息。
  • BLOCK IO:显示块IO相关开销(通用)。
  • CONTEXT SWITCHES:上下文切换相关开销。
  • CPU:显示CPU相关开销信息(通用)。
  • IPC:显示发送和接收相关开销信息。
  • MEMORY:显示内存相关开销信息。
  • PAGE FAULTS:显示页面错误相关开销信息。
  • SOURCE:显示和Source_function。
  • SWAPS:显示交换次数相关开销的信息。

Show Profile查询列表,日常开发需要注意的结论:

  • converting HEAP to MyISAM:查询结果太大,内存都不够用了,往磁盘上搬了。
  • Creating tmp table:创建临时表(拷贝数据到临时表,用完再删除),非常耗费数据库性能。
  • Copying to tmp table on disk:把内存中的临时表复制到磁盘,危险!!!
  • locked:死锁。

12. 全局查询日志

explain,mysqldumpslow,Show Profile 和 全局查询日志 都可以分析sql优化

全局查询日志记录所有sql查询记录(Show Profile的功能更强大)

  • 永远不要在生产环境开启这个功能!

配置启用
mysql高级_第9张图片

编码启用

mysql高级_第10张图片

13.MySQL锁机制

锁是计算机协调多个进程并发访问某一资源的机制。

  • 锁的分类

    • 从对数据操作的类型(读/写)分
      • 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。
      • 写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁。
  • 从对数据操作的粒度分

    • 表锁
    • 行锁
    • 页锁

1.表锁(偏读)

  • 表锁偏向MyISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低。

查看数据库表锁的命令
SHOW OPEN TABLES;

手动增加表锁
lock table 表名字 read(write), 表名字2 read(write), 其他;

释放给表添加的锁
UNLOCK TABLES;

mysql高级_第11张图片
mysql高级_第12张图片
mysql高级_第13张图片

1.表锁分析

show status like ‘table%’;

看看哪些表被加锁了:show open tables;
如何分析表锁定:可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定。
show status like ‘table%’;
这里有两个状态变量记录MySQL内部表级锁定的情况,两个变量的说明如下:
Table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1;
Table_locks_waited:出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1),此值高则说明存在着较严重的表级锁争用情况。

此外,MyISAM的读写锁调度是写优先,这也是MyISAM不适合做写为主表的引擎。因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。

2. 行级锁

  • 偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。

InnoDB存储引擎和MyISAM存储引擎最大不同有两点:一是支持事务,二是采用行锁。
有索引字段加行锁

1. 事务隔离级别

  1. 读已提交
    不可重复读: a事务在事务开启期间,读取到b事务操作数据不一样. (多次查询b事务操作数据不一致)
    mysql高级_第14张图片

或 show variables like ‘transaction_isolation’; 查看

脏读:事务a读到了事务b,读未提交 的数据
不可重复读:提交的修改数据
幻读:提交的新增数据

脏读是事务b里面修改了数据
幻读是事务b里面新增了数据

set autocommit=0; 关闭自动提交
commit;手动提交

2. 无索引行锁升级为表锁

如果在更新数据的时候出现了强制类型转换导致索引失效,使得行锁变表锁,即在操作不同行的时候,会出现阻塞的现象

3. 间隙锁

什么是间隙锁?

当我们用范围条件而不是相等条件检索数据,并请求共享或者排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁,对于键值在条件范文内但并不存在的记录,叫做"间隙(GAP)"。

InnoDB也会对这个"间隙"加锁,这种锁的机制就是所谓的"间隙锁"。

间隙锁的危害

因为Query执行过程中通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值不存在。

间隙锁有一个比较致命的缺点,就是**当锁定一个范围的键值后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。**在某些场景下这可能会対性能造成很大的危害。

4.如何锁定一行

select * from 表 where 某一行的条件 for update;
mysql高级_第15张图片
SELECT …FOR UPDATE在锁定某一行后,其他写操作会被阻塞,直到锁定的行被COMMIT。

5.行锁分析

SHOW STATUS LIKE ‘innodb_row_lock%’;

mysql> SHOW STATUS LIKE 'innodb_row_lock%';
+-------------------------------+--------+
| Variable_name                 | Value  |
+-------------------------------+--------+
| Innodb_row_lock_current_waits | 0      |
| Innodb_row_lock_time          | 124150 |
| Innodb_row_lock_time_avg      | 31037  |
| Innodb_row_lock_time_max      | 51004  |
| Innodb_row_lock_waits         | 4      |
+-------------------------------+--------+
5 rows in set (0.00 sec)

対各个状态量的说明如下:

  • Innodb_row_lock_current_waits:当前正在等待锁定的数量。
  • Innodb_row_lock_time:从系统启动到现在锁定总时间长度(重要)。
  • Innodb_row_lock_time_avg:每次等待所花的平均时间(重要)。
  • Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间。
  • Innodb_row_lock_waits:系统启动后到现在总共等待的次数(重要)。

对于这5个变量,比较重要的是

  • innodb_row_lock_time_avg(等待平均时长)
  • innodb_row_lock_waits(等待总次数)
  • innodb_row_lock_time(等待总时长)
    这三项
    尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手制定优化计划。

优化建议

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
  • 合理设计索引,尽量缩小锁的范围。
  • 尽可能减少索引条件,避免间隙锁。
  • 尽量控制事务大小,减少锁定资源量和时间长度。
  • 尽可能低级别事务隔离。

3.页锁

  • 开销和加锁时间介于表锁和行锁之间。
  • 会出现死锁。
  • 锁定粒度介于表锁和行锁之间。
  • 并发度一般

14.主从复制

关闭虚拟机linux防火墙:service iptables stop

15.日志

1.Bin Log 归档日志(逻辑日志)

mysql高级_第16张图片
mysql高级_第17张图片
mysql高级_第18张图片

2.Redo Log重做日志(物理日志)mysql高级_第19张图片

16. where 1=1 与 count

查询是否存在记录,不关心有多少条记录
SELECT 1 FROM table WHERE a = 1 AND b = 2 LIMIT 1

Mysql中where 1=1 和count(0) 使用小技巧

mysql中使用 where 1=1和 1=0 的作用
where 1=0; 这个条件始终为false,结果不会返回任何数据,只有表结构,可用于快速建表

“SELECT * FROM strName WHERE 1 = 0”;
该select语句主要用于读取表的结构而不考虑表中的数据,这样节省了内存,因为可以不用保存结果集。

create table newtable as select * from oldtable where 1=0;
创建一个新表,而新表的结构与查询的表的结构是一样的。

count
count() count(0) count(1) 没有区别,都会统计包含null的值的项,但 count(field) 则会在查询字段时忽略字段值为null的项。
统计表长时,用count(
) 就可以了,但要统计字段时,需要注意这个问题。

关于count的一些谣言:

1、count()比count(val)更慢!项目组必须用count(val),不准用count(),谁用扣谁钱!

2、count(*)用不到索引,count(val)才能用到。

3、count(*)是统计出全表的记录,是吞吐量的操作,肯定用不到索引。

4、count(1)比count(*)的速度快。

count(1)或者count(0)这个效率快一些.中间的是常量就没什么区别
count(*)这个是最慢的 因为它要先去找*代表的列名是什么。

其实建立了索引后,count(索引)和count(0),差不多。

17. mysql实现rownum,使用mysql查询显示行号

Mysql查询结果带行号【带解析】
SELECT @rowno:=@rowno+1 as rowno,r.* from grade_table r ,(select @rowno:=0) t;

用@rowno这自定义变量显示行号,简洁而实用,
mysql高级_第20张图片
如果有按照某个字段排序,行号会不规则排列,换成先排序,外层加上行号会更加合适。

SELECT @ROWNO := @ROWNO + 1 AS ROWNO, T.*
  FROM (SELECT T.ARTICLE_TITLE, T1. NAME, T.ARTICLE_CREATEDATE
          FROM T_ARTICLE T
          LEFT JOIN T_ARTICLE_TYPE T1
            ON T.TYPEID = T1. NAME
         WHERE T.ARTICLE_TITLE LIKE '%博士%'
         ORDER BY ARTICLE_CREATEDATE DESC) T,
       (SELECT @ROWNO := 0) T3
 ORDER BY ROWNO

18. mysql内置功能

  • 视图 view
  • 触发器 trigger ,无法由用户直接调用,被动触发.(begin after), new表示即将插入的行,old表示即将删除的行
  • 事务
  • 存储过程procedure . 调用call. 参数 in(out,inout) 变量名 类型, 有参调用
set @x=0 
p(1,2,@x);
select @x;
  • 流程控制

你可能感兴趣的:(数据库,mysql,b树,数据库)