zoukankan      html  css  js  c++  java
  • MySQL优化 MySQL锁

    一、SQL性能下降慢的原因:

    1. 查询语句写的烂
    2. 索引失效(单值 复合 )
    3. 关联查询太多join(有些是设计缺陷和不得以的需求)
    4. 服务器调优和各个参数的设置。

    二、SQL JOINS

    1、内连接:select * from A inner join B on A.key = B.key

    2、左连接:select * from A left join B on A.key = B.key

    3、右连接:select * from A right join B on A.key = B.key

    4、select * from A left join B on A.key = B.key where B.key is null;

    5、select * from A right join B on A.key = B.key where A.key is null;

    6、全连接select * from A full outer join B on A.key = B.key ;(MySql不支持)

    MySql:select * from A left join B on A.key = B.key union select * from A right join B on A.key = B.key

    7、select * from A full outer join B on A.key = B.key where A.key is null or B.key is null;

    mysql:

    select * from A left join B on A.key = B.key where B.key is null union select * from A right join B on A.key = B.key where A.key is null

    三、索引:

    1、定义:

    sql官方:索引(index)帮助mysql高效获取的数据结构。

    • 类似字典,例如查找“mysql” 先查m,再查y 依次..

    • 简单的理解:排好序的快速查找数据结构。

    • 数据本身之外,数据库还维护着一个满足特定的查找算法的数据结构,这些都是数据结构以某种方式指向数据,这样就可以在数据结构上实现高级查找算法。这种数据结构就是索引。

    • 一般来说索引本身很大,不可能全部存储在内存中,因此索引以文件的方式存储在磁盘上。

    2、优缺点:

    • 优点:(1)提高检索效率,减少io操作成不。(2)降低数据排序的成本,降低cpu消耗。

    • 缺点:(1)索引实际上也是一张表,索引列也会占空间 (2)进行insert,update,delete操作时,mysql不仅要保存数据,还要保存每次更新索引列的字段。(3)如果有大量数据表,需要花时间来分析用户最喜欢的查询条件,逐步优化,找到最优建立索引的方式。

    3、索引分类:

    单值索引:索引只包含单个列,一个表可以有多个单列索引,一个表最好不要不要超过5个(一条查询语句只能使用一个索引)。

    唯一索引:索引列的值必须唯一。可为null

    复合索引:一个索引包含多个列

    ​ 创建:create index indexName on tableName(aa,aa)

    ​ alter tableName ADD INDEX [indexName] ON (aa,aa)

    ​ 删除:drop index[indexName] on table;

    ​ 查看:show index from tableName G

    4、那些情况可以建立索引:

    • 主键自动建立索引。
    • 频繁作为查询条件的字段。
    • 查询中与其他表关联的字段,外键关系建立索引。
    • 频繁更新不适合,每次更新都会更新表和索引文件。
    • where 条件里用不到的字段不创建索引。
    • 单键/复合?选择复合
    • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。
    • 重复且平均分配的字段建索引优化的效果不大(例:男/女)

    5、性能分析:

    explain:查询执行计划 explain+sql语句

    作用:

    • 表的读取顺序

    执行计划所包含的信息:

    id select_type table type possible_keys key key_len ref rows extra
    id

    id相同,执行顺序由上至下。

    如果是子查询,id号会递增,id值越大优先级越高,越先被执行。

    id相同/不同:id相同,认为是一组,执行顺序由上至下。id值越大优先级越高,越先被执行。

    select_type

    SIMPLE:简单select 不包含子查询 /union

    PRIMARY:最后加载的

    SUBQUERY:包含子查询

    DERIVED:

    UNION:

    UNION RESULT:

    type

    显示查询使用了何种类型。

    从最好到最差

    system>const>eq_ref>ref>range>index>all(全表查询)

    system:表只有一行记录等于系统表

    const:通过索引一次就可以找到

    eq_ref:通过索引查询,表刚好只有一个记录与之匹配。

    ref:

    range:检索给定范围的行,查询语句中出现了< > between

    index:index与all区别,只遍历树。

    all :全表扫描。

    possible_keys/key

    显示可能应用到这张表的索引,一或多个。查询涉及到字段上的索引,则该索引别列出。但不一定实际使用。

    key

    实际使用的索引,如果为null,则未使用(索引失效)

    若查询中使用了覆盖索引,则该索引仅出现在key列表中(理论上不会使用索引,实际上使用了)。所查的字段,正好和索引吻合。

    例子 select col1,col2 from tb 而建的索引中也有 crate index idx_Name tb(col1,col2) 刚好吻合。

    key_len

    索引中使用的字节数,索引字段可能出现的最大长度。并非实际长度,根据定义所得,并不是检索所得。

    rows

    大致估算出找到所要的记录,需要读取的行数。

    6、两表优化:

    左连接:给右表建索引

    右连接:给左表建索引

    7、三表优化

    与两表优化类似,左连接 给二、三表加索引。

    8、索引失效

    1、最佳左前缀法则(查询从索引的最左开始,中间不能断) crate index indexName(name,age,pos) 执行select name,age,pos from是最优的,但是当丢失name(select age,pos from)索引失效 类似:(select pos from)也失效。(select name)不失效。(select name,pos)失效。

    2、不要在索引列中做任何操作(计算,函数,类型转换)

    例如:select * from staff where left(name,4)='july' ,索引失效

    3、范围之后全失效 select name,age,pos from tb where name='haha' and age>25 pos='bb' ,从age开始全失效。

    4、按需写(用什么取什么),尽量索引列和查询列一致,少用select *

    5、在使用使用不等于!= 或者 <>的时候会导致索引失效。从而全表扫描。但是不代表不用。 该写还得写。

    6、is null 和is not null无法使用索引。建议避免空值 最好写入default

    7、like以通配符开头(“%abc...”)后面查询索引会失效。%abc%失效 abc不失效。

    crate index indexName on tb(name,age) 使用select * from like 导致失效。正确理解覆盖索引:查询的语句不能超过建立索引的大小。例如建立索引为(name,age)而查询的为select name,age,email. 超过索引范围,导致失效。

    8、字符串不加单引号索引失效。未加‘’ mysql会进行隐式类型转换。

    9、少用or ,用它连接会导致索引失效。

    小结:

    index(a,b,c)

    where a=3 and b="ab%" and c=4 用到abc

    where a=3 and b="%ab" and c=4 用到a

    where a=3 and b="%ab%" and c=4 用到a

    where a=3 and b="a%ab%" and c=4 用到abc 因为左边是定值。

    index(c1,c2,c3)

    explain select * from test03 c1='a1' and c2='a2' and c5='a5' order by c3 ,c2; 不会出现内排序(using filesort)因为c2已经是定值例如都等于1了,排序没有意义。

    explain select * from test03 c1='a1' and c5='a5' order by c3 ,c2; 会出现内排序,影响sql的查询性能。

    9、查询分析

    1. 观察 ,至少跑一天,看看慢sql情况
    2. 开启慢查询日志,超过5秒就是慢sql
    3. explain+加慢sql分析
    4. show profile
    5. DBA 参数调优

    优化原则:小表驱动大表

    order by

    mysql支持两种排序方式,filesort和index ,index效率高,它指mysql扫描索引本身完成排序。filesort方式效率较低。

    order by满足两种情况使用index :

    提高order by的速度:少用select * ,写需要query的字段。

    group by

    与order by类似 order by是先排序 group by是先分组

    Max()

    通过索引的方式优化

    查询最后支付的时间:explain select max(payment_date) from payment

    优化:对payment_date建立索引

    create index idx_paydate on payment(payment_date);

    索引顺序排列,不用直接去查询表的信息,直接获取顺序排列后的最后一个值。查询的时间是恒定的。

    Count()

    在一条sql中,同时查询2006和2007年的数量

    select count(release_year ='2006' or null) as '2006年电影数量', count(release_year='2007' or null) as '2007年电影数量' from film;

    解释:count函数中,不会记录空值。使用count(*)会将空值记录进去。造成结果不一致。

    子查询优化

    通常情况下,需要把子查询优化成join的方式查询,但是在优化时,注意一对多的关系,使用distinct 关键词去重。

    原sql:select * from t where t.id in (select t1.tid from t1);

    优化:select distinct t.id from t join t1 on t.id=t1.tid;

    limit

    limit常用于分页处理,时常伴随着order by从句使用。

    原sql :select film_id,description from sakila.film order by title limit 50,5

    优化:select film_id,description from sakila.film order by film_id limit50,5

    解释:使用主键film_id排序,使用了索引。随着翻页的次数增多,查询的行数变多。

    再次优化:记录上一次访问主键的id,再次操作时,经过主键过滤。

    select film_id,description from sakila.film where film_id>55 and film<=60 order by film_id limit50,5

    注意:此次改写,需要主键连续,中间不能有间隔,通过主键过滤,不在扫描之前的。效率比较固定。

    四、对mysql日志进行分析

    官方自带分析工具:mysqldump

    mysqldumpslow -h:查看每个参数含义

    分析工具pt-query-digest

    查看mysql是否开启慢查询日志:show VARIABLES like 'slow_query_log'

    查看超过多少时间的查询写入日志:(默认10s)show VARIABLES LIKE 'long_query_time'

    设置记录时间为0s,方面查看:SET GLOBAL long_query_time = 0

    开启慢查询日志:set GLOBAL slow_query_log=ON

    设置慢查询日志存放位置:set global slow_query_log_file='/home/mysql/sql_log/mysql-slow.log'

    设置是否将没有使用索引的sql语句记录在日志中:set GLOBAL log_queries_not_using_indexes=ON

    设置超过一秒的时查询,就把它记录在慢查询日志中:set global long_query_time=1

    image-20200914175015734

    Show profile

    用于SQL的调优测量。查看sql执行的完整生命周期。

    MySQL锁

    分类:

    • 对于数据操作类型:读/写

    • 对于数据操作的粒度:表锁/行锁

    读锁(共享锁):针对同一数据,多个读操作互不影响

    写锁(排它锁):当前写操作未完成前,会阻断其他写锁和读锁。

    1、表锁

    (偏读):开销小,加锁快。

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

    show open tables; //查看那些表加锁

    unlock tables; //释放锁

    加读锁

    session-1 session-2
    mylock表加读锁
    当前session可查看该表 其他session可查看该表
    当前session不可查其他未锁定的表 其他session可查看其他未锁定表
    当前session不可更新当前锁定的表 其他session更新该表,会阻塞等待
    释放锁 获得锁,插入操作完成

    加写锁

    session-1 session-2
    mylock表加写锁
    当前session可查询更新表 其他session对它查询阻塞,需要等待释放
    释放锁 获得锁,可查询

    总结:读锁会阻塞写,不阻塞读。写锁,会阻塞读和写。

    2、行锁

    innoDB,开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突低,并发度最高。

    复习:事务的ACID原则

    事务具有四个特征,分别足原子性(Atomicity )、一致性(Consistency )、隔离性(Isolation) 和持久性(Durability)
    
    • 原子性(Atomicity)
      原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

    • 2、一致性(Consistency )
      事务前后数据的完整性必须保持一致。如果数据库系统在运行过程中发生故障, 有些事务尚未完成就被迫中断,这些未完成的事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。

    • 3、隔离性(Isolation)
      事务的隔离性是指在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。

    • 4、持久性(Durability)
      持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

    理解:https://blog.csdn.net/dengjili/article/details/82468576

    并发事务带来的问题

    更新丢失:

    多个事务,对同一数据进行操作,由于不知道彼此的存在,最先修改的数据,被后来的事务修改。

    脏读:

    事务A读取到事务B已修改尚未提交的数据。事务B可能发生回滚,导致数据失效。

    不可重复读:

    一个事务在读取数据后的某个时间,再次读取以前读过的数据,发现不一致。

    事务A读取到事务B已经提交的数据。不符合隔离性。

    例子:事务A开启事务-->查出银行卡余额为1000元,此时切换到事务B事务B开启事务-->事务B取走100元-->提交,数据库里面余额变为900元,此时切换回事务A,事务A再查一次查出账户余额为900元,这样对事务A而言,在同一个事务内两次读取账户余额数据不一致,这就是不可重复读。

    幻读:

    一个事务按查询条件读取以前检索过的数据,发现其他事务也插入了满足查询条件的新数据。

    例子:比如学生信息,事务A开启事务-->修改所有学生当天签到状况为false,此时切换到事务B,事务B开启事务-->事务B插入了一条学生数据,此时切换回事务A,事务A提交的时候发现了一条自己没有修改过的数据,这就是幻读,就好像发生了幻觉一样。幻读出现的前提是并发的事务中有事务发生了插入、删除操作。

    一句话:事务A读取到了事务B提交的新增数据。

    ​ 脏读是事务B里面修改了数据。

    ​ 幻读是事务B里面新增了数据。

    事务的隔离级别

    解决上面几种问题而诞生的,事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡。

    img

    无索引行锁变表锁

    间隙锁

    session1

    session2

    session1操作的数据没有2,但是session2,对2行无法进行操作。原因:会锁定范围之内的所有数据不管中间是否为空。只能等session1提交后才能执行。

    什么是间隙锁:

    当我们用范围条件而不是相等条件检索数据,并请求共享或排它锁时,innodb会给符合条件的加锁。对于在条件内并不存在的记录,叫做间隙。

    锁定某一行

    select * from test where a =8 for update; 锁定后,对该行的其他操作会阻塞。直到commit

  • 相关阅读:
    设定cookie 获取cookie数据的转换
    cookie cookie的获取
    常见的请求方式 json字符串
    请求报文和响应报文
    http协议
    php分页查询 子查询
    MAC 地址为什么不需要全球唯一
    ceph分布式存储简介
    一文看懂为什么边缘计算是大势所趋
    真香!Windows 可直接运行 Linux 了
  • 原文地址:https://www.cnblogs.com/xiaolaodi1999/p/13687382.html
Copyright © 2011-2022 走看看