目录

​上次我们讨论了MySQL的运行流程及原理,字段设计,存储引擎和查询缓存。

这次我们继续来追命连环问关于事务,索引,SQL优化等相关的内容。准备好了吗?事务

索引

SQL优化

常见问题

1. MySQL事务

面试官:你知道事务吗?

我:知道。事务(Transaction)是访问和更新数据库的程序执行单元;

事务中可能包含一个或多个sql语句,这些语句要么都执行,要么都不执行。

事务主要有四大特性。即ACID:原子性,一致性,隔离性和持久性。

原子性:不可分割的操作单元,事务中所有操作,要么全部成功;要么回滚到执行事务之前的状态。

一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

隔离性:事务操作之间彼此独立和透明互不影响。如果一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。

持久性:事务一旦提交,其结果就是永久的。即便发生系统故障,也能恢复。

面试官:嗯四大特性说的没错,那你知道高并发场景下事务可能会出现的问题吗?

我:事务并发执行的话确实会产生一些问题。比如说:幻读,脏读,不可重复读。因为隔离性脏写是不会发生的。

脏读:一个事务读取到另一个未提交事务修改的数据。

session A:查询,得到某条数据

session B:修改某条数据,但是最后回滚掉啦

session A:在sessionB修改某条数据之后,在回滚之前,读取了该条记录

对于session A来说,读到了session回滚之前的脏数据

不可重复读:多次读取的数据内容不一样。

session A:查询某条记录

session B : 修改该条记录,并提交事务

session A : 再次查询该条记录,发现前后查询不一致

幻读:前后多次读取,数据总量不一样。

session A:查询表内所有记录

session B : 新增一条记录,并查询表内所有记录

session A : 再次查询该条记录,发现前后查询不一致

面试管:那什么情况下会出现这些问题呢?

MySQL标准中定义了四种隔离级别,并规定了每种隔离级别下上述几个问题是否存在。

一般来说,隔离级别越低,系统开销越低,可支持的并发越高,但隔离性也越差。隔离级别与读问题的关系如下:

读未提交:脏读,不可重复读,幻读都有可能发生

读已提交:不可重复读,幻读可能发生

可重复读:幻读可能发生

可串行化:都不可能发生

在实际应用中,读未提交在并发时会导致很多问题,而性能相对于其他隔离级别提高却很有限,因此使用较少。

可串行化强制事务串行,并发效率很低,只有当对数据一致性要求极高且可以接受没有并发时使用,因此使用也较少。

因此在大多数数据库系统中,默认的隔离级别是读已提交(如Oracle)或可重复读。

MySQL事务默认的隔离级别是可重复读,而且MySQL可以解决了幻读的问题。

面试官:看来你对事务理解的还不错。那你知道MySQL的另一个重要特性索引吗?

2. MySQL索引

答:索引就是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。

在数据之外,数据库维护这些原来快速查找的索引也是要付出代价的。一是增加了数据库的存储,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。

面试官:那索引是怎样实现的呢?MyISAM和Innodb的实现方式一样吗?

答:不一样的。MyISAM和Innodb虽然都使用B+树作为索引结构,但索引的实现方式还是不一样的。

MyISAM的叶节点的data域存放的是数据记录的地址,而Innodb数据文件本身就是索引文件。

MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。

MyISAM索引

而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。

Innodb索引

因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有)。

如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键。

B+树是一种B树的变种,为有序数组链表+平衡多叉树。基本和B树类似,只有叶子节点存放数据,而且叶子节点之间通过指针相连。

面试官:那为什么索引用B+树呢,B+树有什么优点呢?

1、B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。

2、由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。

面试官:那什么是聚簇索引呢?

聚簇索引是一种数据存储方式,它实际上是在同一个结构中保存了B+树索引和数据行,InnoDB表是按照聚簇索引组织的。

InnoDB通过主键聚簇数据。他使用主键值的大小来进行记录和页的排序。叶子节点存储的是完整的用户记录。注:聚簇索引不需要我们显示的创建,他是由InnoDB存储引擎自动为我们创建的。如果没有主键,其也会默认创建一个。

但聚簇索引只有在搜索条件为主键是才发挥作用,如果为其他的字段就不行,这个时候就需要普通索引了。

二级索引的叶子节点不再是完整的数据记录,而是字段和主键值。当需要这条记录的其他字段时仍然需要根据这个主键id去查询,这个步骤叫做回表。

聚簇索引表最大限度地提高了I/O密集型应用的性能,但它也有以下几个限制:插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。

更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新的。

二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。

面试官:索引有哪些类型?索引越多越好吗?

除了上面说的主键索引和普通索引,还有唯一索引,联合索引和全文索引。

唯一索引:该列具有唯一性的同时又是索引,不允许重复。

全文索引:主要用于文本的查询,它的出现是为了解决WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题。

联合索引:对多列值进行一个索引,其效率大于索引合并。需遵循前缀原则。

建索引是有开销的所以也不是越多越好,只要在需要的字段上建立索引。

第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。

第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

索引的使用需要注意以下几点:

1.最左前缀原则。一个联合索引(a,b,c),如果有一个查询条件有a,有b,那么他则走索引,如果有一个查询条件没有a,那么他则不走索引。

2.使用唯一索引。具有多个重复值的列,其索引效果最差。

3.不要过度索引。每个额外的索引都要占用额外的磁盘空间,并降低写操作的性能。在修改表的内容时,索引必须进行更新,有时可能需要重构,因此,索引越多,所花的时间越长。

4、索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);

5.一定要设置一个主键。前面聚簇索引说到如果不指定主键,InnoDB会自动为其指定主键,这个我们是看不见的。反正都要生成一个主键的,还不如我们设置,以后在某些搜索条件时还能用到主键的聚簇索引。

6.主键推荐用自增id,而不是uuid。上面的聚簇索引说到每页数据都是排序的,并且页之间也是排序的,如果是uuid,那么其肯定是随机的,其可能从中间插入,导致页的分裂,产生很多表碎片。如果是自增的,那么其有从小到大自增的,有顺序,那么在插入的时候就添加到当前索引的后续位置。当一页写满,就会自动开辟一个新的页。

索引禁忌:不在低区分度的列上建⽴索引,例如“性别”

尽量避免%前导的查询,如like “%ab”

尽量避免负向查询,如not in/like

避免全表扫描和频繁的回表操作

面试官:看来你对索引掌握的很不错啊,那你平常遇到慢查询是怎么优化的呢?

3. SQL优化

SQL语句从客户端经由网络协议到查询缓存,如果没有命中缓存,再经过解析工作,得到准确的SQL然后再来到优化器。

首先,我们知道每一条SQL都有不同的执行方法,要不通过索引,要不通过全表扫描的方式。

影响SQL速度的主要在I/O成本和CPU成本的消耗上。

数据存储在硬盘上,我们想要进行某个操作需要将其加载到内存中,这个过程的时间被称为I/O成本。在内存对结果集进行排序的时间被称为CPU成本。

所以进行sql优化首先进行索引优化,让我们的sql语句尽量走索引而不是走全表扫描的方法。

在平常遇到慢查询时首先去分析慢查询日志,找出慢查询的sql。然后针对这些sql进行分析。常见慢查询主要有以下几种情况:索引没起作用。字段没建立索引,或者是索引没有起作用。使用了like关键字或使用了多列索引的查询语句。

数据库结构不合理。合理的数据库结构不仅可以使数据库占用更小的磁盘,也可以让sql执行速度更快。一可以将字段很多的表拆解成多个表。二增加中间表。

分解关联查询。将大查询分成多个小查询。

优化limit分页。当偏移量非常大时会导致前面查询到的无用数据都要舍弃掉,如果表非常大,且筛选字段没有合适的索引,那么这样的代价是非常高的。如我们下一次的查询能从前一次查询结束后标记的位置开始查找,那将节省很多开销。

4.常见问题

问题一:嗯现在我们来看看具体问题,那你看这条语句会用到索引吗?以下语句是否会应用索引:SELECT FROM users WHERE YEAR(adddate) < 2007;

答:不会,因为只要列涉及到运算,MySQL就不会使用索引。

问题二:那如果列值为NULL时,查询是否会用到索引?

在MySQL里NULL值的列也是走索引的。当然,如果计划对列进行索引,就要尽量避免把它设置为可空,MySQL难以优化引用了可空列的查询,它会使索引、索引统计和值更加复杂。

问题三:索引一定会提高速度吗?

通常,通过索引查询数据比全表扫描要快。但是我们也必须注意到它的代价。

索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时,索引本身也会被修改. 这意味着每条记录的INSERT,DELETE,UPDATE将为此多付出4,5 次的磁盘I/O. 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能。

问题四:如何查询第n高的工资?

SELECT DISTINCT(salary) from employee ORDER BY salary DESC LIMIT n-1,1

问题五:一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录。

1、如果A表TID是自增长,并且是连续的,B表的ID为索引

select * from a,b where a.tid = b.id and a.tid>500000 limit 200;

2、如果A表的TID不是连续的,那么就需要使用覆盖索引。TID要么是主键,要么是辅助索引,B表ID也需要有索引。

select * from b , (select tid from a limit 50000,200) a where b.id = a .tid;

好啦,今天的追命连环问就到这里了,下次继续,如对文章有疑惑或补充的地方欢迎留言交流(●'◡'●)。原创不易,如果对你有帮助的话欢迎点赞!

相关推荐阅读

mysql添加二级索引的sql语句_MySQL面试知识点追命连环问(二)事务、索引及SQL优化...相关推荐

  1. MySQL面试知识点追命连环问(三)锁机制、日志备份及分表策略

    ​上次我们讨论了MySQL的事务索引,SQL优化和处理器. MySQL面试知识点追命连环问(二)事务.索引及SQL优化 这次我们继续来追命连环问关于MySQL锁机制,日志备份和扩展性等相关的内容. 锁 ...

  2. MySQL面试知识点追命连环问(一)执行流程存储引擎查询缓存

    ​来了,朋友们,追命连环问系列之MySQL部分开始了.准备好了吗?本次连环问主要设计以下四个方面: MySQL执行流程 MySQL存储引擎 表字段如何设计 查询缓存 一,MySQL的执行流程 面试官: ...

  3. mysql log 记录报错 sql语句_MySQL生产库中添加修改表字段引起主从崩溃的问题总结...

    上周末和开发人员对线上库中的部分表的在线DDL和update,这过程中出现了一些意料之外的问题,现将过程.分析和解决方案在这里总结一下 一. 需求背景: 要在如下表中添加字段(modified_at) ...

  4. mysql组合索引sql语句_mysql操作索引的sql语句

    创建索引 一:唯一索引 alter table table_name add unique index_name(column_list); 例如:alter table users_game_tas ...

  5. mysql 主键 sql语句_Mysql 增加主键或者修改主键的sql语句操作

    添加表字段 alter table table1 add transactor varchar(10) not null; alter table table1 add id int unsigned ...

  6. 数据库——python操作MySQL、修改表SQL语句、视图、触发器、存储过程、事务、流程控制、常见函数、索引

    文章目录 一.python操作MySQL 1.pymysql模块 1.基本使用 2.sql注入问题 3.二次确认 二.修改表SQL语句 1.修改表的名字 rename 2.添加字段 add 3.修改字 ...

  7. mysql 怎么查询慢sql语句_Mysql中 查询慢的 Sql语句的记录查找

    Mysql中 查询慢的 Sql语句的记录查找 慢查询日志 slow_query_log,是用来记录查询比较慢的sql语句,通过查询日志来查找哪条sql语句比较慢,这样可以对比较慢的sql可以进行优化. ...

  8. mysql查询主键sql语句_MySQL数据库-表操作-SQL语句(一)

    1. 数据库操作与存储引擎 1.1   数据库和数据库对象 数据库对象:存储,管理和使用数据的不同结构形式,如:表.视图.存储过程.函数.触发器.事件等. 数据库:存储数据库对象的容器. 数据库分两种 ...

  9. mysql 输出参数 sql语句_MySQL: 详细的sql语句

    1添 1.1[插入单行] insert [into] (列名) values (列值) 例:insert into Strdents (姓名,性别,出生日期) values ('开心朋朋','男',' ...

最新文章

  1. 男人约会动机大揭秘。
  2. php跳出volist,thinkphpvolist
  3. json和jsonp(json是目的,jsonp是手段)
  4. 《深入浅出MFC》第六章 MFC程序的生死因果
  5. 跟着别人的感觉做网络推广之二
  6. 【笔试】:编程实现C++string 类成员函数
  7. impdb导入oracle,impdp导入.dmp到oracle
  8. 携程apollo系列-个人开发环境搭建
  9. python模块与类的区别_Python类、模块、包的概念及区别
  10. vs2005中分割线怎么插入
  11. 从零开始实现 AlphaGo(一)
  12. 八大数据分析模型之——用户模型(一)
  13. 随笔记:PPT渐变色
  14. java开发速成班培训课程(1)
  15. 《输赢》精彩段落总结
  16. 驳“C语言已经死了”
  17. 医疗器械小程序或手机APP软件开发方案
  18. Mysql 聚集索引和非聚集索引区别
  19. 支持360打倒无耻的tx
  20. win2008 Server R2 中IIS启用TLS 1.2 工具 一键开启TLS 1.2

热门文章

  1. springboot配置mybatis redis缓存
  2. MySQL为什么使用B+树作为索引? 索引原理?
  3. html5文章标题定格,jQuery和css3文章标题动画特效
  4. 真无线蓝牙耳机选购小知识,全网口碑前五的真无线蓝牙耳机测评
  5. python怎么保存为nii文件_python处理nii文件
  6. Python合并文件夹下的图片并按序号重命名
  7. 第7-2课:垃圾邮件过滤与贝叶斯分类算法
  8. 什么是 ARP 攻击?
  9. ProcessingJoy —— 简单的 3D 文字【JAVA】
  10. Mplayer快捷键一览表