必知必会的高级MySQL

程序员必会的SQL调优

首先了解数据库存储两大常用引擎 Innodeb和MyISAM

数据库引擎 存储方式 底层结构 事务 索引 主外键
MyISAM 存储三个文件frm表结构和myd数据和myi索引 B树 No 行级锁 非聚集 No
Innodeb 存储两个文件 frm表结构和myd数据 B+树 Yes 行级锁和表级锁(默认) 聚集索引 Yes

B树是每一个节点都存在key和访问磁盘value的索引,B+树是叶子节点才存数据值,其它都是索引

索引类型

单值索引where name=‘xxx’ 复合索引where name=‘xx’ and email=‘xxx’ 唯一索引:值得是唯一值的

create index idx_user_name on user(name) //单值

create index idx_user_nameEmail on user(name,email) //复合

create unique index idx_user_id on user(id) //

Sql执行顺序

必知必会的高级MySQL_第1张图片

什么是索引

索引本质是数据结构,目的是提高查找效率,排好序的快速查找数据结构就是索引

数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,比如B树和B+树

B树

叶子节点存储的是磁盘数据的地址

必知必会的高级MySQL_第2张图片

查询快,但是增删慢,因为每次修改,还要修改指向数据的索引

优势: 提高检索效率,降低数据排序成本,避免全盘扫描

索引不是越多越好

索引也是一张表,保存了主键与索引字段,所以也占内存,

而且虽然提高查询速度,但是降低更新表的速度,因为mysql不仅要保存数据,还要保存一下索引文件每次更新添加的索引列字段,都会调整更新后带来的键值变化的索引

如果一个表没有建索引,会自动以主键为索引,如果没有主键,会自动选取一个不为空的当主键

索引场景

  1. 主键自动唯一索引
  2. 频繁查询的字段
  3. 查询中与其它表关联的字段,外键关系建立索引
  4. where里用不到的字段不创建索引
  5. 高并发组合索引比较好
  6. 频繁更新的字段不要建立索引
  7. 太多重复内容

EXPLAIN使用

explain+sql
explain select * form user

id能判断Sql执行顺序

  1. id表示执行加载顺序 id越大越先执行,id全相同由上至下,id混合
  2. select_type:primary代表最外层查询,最后被执行,从最里层开始执行到最外层
  3. table :dervide 衍生表

select_type 表示sql操作的类型

  1. simple,简单的select查询
  2. primary,外层鸡蛋壳
  3. subquery,在Select或where包含了子查询
  4. derived,子查询起了别名表,会暂时放在临时缓存里
  5. union, 联合查询

table表名

就是说明该行数据关联了哪个表执行

type 访问类型

syetem>const>eq_ref>ref>range>index>All

  1. all 全盘扫描
  2. syetem,表只有一行记录,系统表,平时不会出现,忽略不计
  3. const 表示通过一次索引就找到了,如where 主键,只匹配一行数据
  4. eq_ref 唯一性索引扫描,主键两个情况
  5. ref 非唯一,可能找出多个符合条件
  6. range 范围查询

possible_keys 显示可能应用的索引

key实际使用的索引 null为没有使用

key_len 索引使用的字节数

ref 显示索引哪一行被使用

rows 大致估算读取的行数才能出结果

Extra 额外重要信息显示

  1. useing filesort 文件内排序
  2. useing temporey 使用临时表
  3. useing index 使用索引找到数据
  4. useing where 范围找
  5. covering index 刚好索引对于查询的

索引注意点

  1. 单表连接 如果是直接索引改的话,可以把type从all改为ref,因为一旦遇到了范围查询索引就会失效 type就会是range

  2. 双表连接 相反键

    如果是左连接,那索引建在左边,没效果,因为左连接就是含左表所有记录,建在右边,会减少很多rows

  3. 三表连接 都是左连接设置给后两行,rows会变少,然后type是ref

  4. 优先优化最里层的,然后就是尽可能减少join循环次数,然后用小表来连接大表

  5. 当无法得知join的字段是否有索引的时候,且内存充足的话可以调大joinBuffer的大小,来缓存

索引失效

  1. 全值匹配,然后如果是建立了三个索引的复合索引,但是where没有从第一个开始(火车头,最左匹配原则)

  2. 全值匹配我最爱,中间兄弟不能断,

  3. 函数自动转换或者计算会失效索引,范围之后全失效

  4. 使用不等于会使索引失效

  5. is null ,is not null 也会使索引失效

  6. 尽量使用覆盖索引,索引列和查询列一致,之访问索引的查询,减少select *

  7. like以%开头会使索引失效,百分like加右边

如何解决like%写右边索引失效

比如 给name 和age建立索引,两个%不会失效索引

用覆盖索引来避免全盘扫码

  1. varchar类型绝对不能失去单引号,数字失去的话会自动转换,但是会失去索引
  2. 少用or,用它连接索引会失效
  3. 最佳左匹配原则
【优化总结口诀】
全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
Like百分写最右,覆盖索引不写星;
不等空值还有or,索引失效要少用;
VAR引号不可丢,SQL高级也不难!

局部性原理

每次取数据都是按页取,Innodb是16kb,MYyISAM是4kb

慢Sql的分析,排除

  1. 观察,先跑一天,看看生产的慢SQL情况
  2. 开启慢查询日志,设置超过一定时间就算是慢sql,然后提取出来
  3. explain对sql进行分析
  4. show profile sql执行细节和生命周期情况
  5. 运维对sql服务器的参数调优

慢查询日志

set global slow_query_log=1;

show variables like ‘%slow_query_log%’;

会出现slow_query_log_file地址

set global long_query_time=3; //修改慢查询阈值

打开log文件

show global status like ‘Slow_queries%’; //打印慢sql条数

mysqldumpslow 日志分析

ShowProfile

是mysql可以用来分析当前会话中语句执行的资源消耗情况,

默认保存最近15次运行结果,默认关闭set profiling=on

然后会显示sql ,id,执行时间,

再show profile cpu,block io for query id查看sql执行生命周期

数据库锁

按操作来分有读锁和写锁

可以想想读写锁,读锁可以共享同时,但是写锁是独占的不能和读锁一起,也不能和写锁一起

lock table 表名 read,表名 write;

unlock tables;释放表锁

MYIASAM是写锁优先,不适合作为查询的数据库引擎,适合写的场景,比如店家上架

按照类别分有表锁和行锁

表锁粒度大,效率低,容易死锁,冲突高

行锁粒度小,效率高,页锁,发生锁的冲突低,并发级别高

数据库事务

Innodeb支持

什么是事务,事务是保证业务要么成功要么失败的方案,具有ACID属性

A 原子性 要么双方一起成功要么一起失败

C 一致性 成功后的总合和之前的总合应该相等,质量没有变化

I 隔离性 每个事务的执行不会影响其它的事务,且事物内部对外部不可见

D 持久性 事务完成,数据永久保存在数据库中

更新丢失

两个事务都同时更新一行数据,一个事务对数据的更新把另一个事务对数据的更新覆盖了。这是因为系统没有执行任何的锁操作,因此并发并没有被隔离开来。

脏读

一个事务读取到了另一事务未提交的数据操作结果。这是相当危险的,因为很可能所有的操作都被回滚。

A修改数据之前,有200快,B查到了未提交的200,A这时候扣了100块,提交完是100,B却是查到未提交的之前的200

不可重复读(修改)

一个事务对同一行数据重复读取两次,但是却得到了不同的结果

  • 虚读:事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读取该数据时得到与前一次不同的值。

Mysql默认是可重复读

幻读(新增和删除)

  • 幻读:事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据。这是因为在两次查询过程中有另外一个事务插入数据造成的。

事务隔离级别

必知必会的高级MySQL_第3张图片

必知必会的高级MySQL_第4张图片

未提交读: 可以处理更新丢失,如果一个事务已经开始写数据,则不允许其他事务同时进行写操作,但允许其他事务读此行数据。可通过“排他写锁”实现。

提交读: 处理更新丢失、脏读。读取数据的事务允许其他事务继续访问改行数据,但是未提交的写事务将会禁止其他事务访问改行。可通过“瞬间共享读锁”和“排他写锁”实现。

可重复读取(Repeatable Read): 处理更新丢失、脏读和不可重复读取。读取数据的事务将会禁止写事务,但允许读事务,写事务则禁止任何其他事务。可通过“共享读锁”和“排他写锁”实现,别人在读的时候不允许其它人写

序列化(Serializable): 提供严格的事务隔离。要求失去序列化执行,事务只能一个接一个地执行,不能并发执行

隔离级别越高,越能保证数据的完整性和统一性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

你可能感兴趣的:(数据库,mysql,数据库,数据结构)