MySql相关内容

96 阅读8分钟

image.png

1、事务

隔离级别

读未提交:可能出现脏读、幻读、不可重复读

读已提交:可能出现幻读、不可重复读

可重复读:可能出现幻读

可串行化:串行执行

MVCC:

MVCC 的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖记录中的 3个隐式字段,undo日志 ,Read View 来实现的。

image.png

事务开始时会生成一个读视图Read View,记录并维护系统当前活跃事务的ID;

Read View遵循一个可见性算法,主要是将要被修改的数据的最新记录中的 DB_TRX_ID(即当前事务 ID )取出来,与系统当前其他活跃事务的 ID 去对比(由 Read View 维护),如果 DB_TRX_ID 跟 Read View 的属性做了某些比较,不符合可见性,那就通过 DB_ROLL_PTR 回滚指针去取出 Undo Log 中的 DB_TRX_ID 再比较,即遍历链表的 DB_TRX_ID(从链首到链尾,即从最近的一次修改查起),直到找到满足特定条件的 DB_TRX_ID , 那么这个 DB_TRX_ID 所在的旧记录就是当前事务能看见的最新老版本。

image.png

image.png

redo log:重做日志,保证事务的持久性

undo log:保证事务的一致性

bin log:操作日志,用于主从同步和恢复

2、锁

全局锁:一般备份或者恢复是加锁

表锁

页锁

行锁:分共享锁(S锁)和排它锁(X锁)

间隙锁

3、索引

InnoDB支持的索引:

B+树索引

全文索引

哈希索引

采用B+ tree存储数据

B+树的高度一般都在2~4层,

每页大小16K

4、建立索引的原则

1.最左前缀匹配原则。这是非常重要、非常重要、非常重要(重要的事情说三遍)的原则,MySQL会一直向右匹配直到遇到范围查询(>,<,BETWEEN,LIKE)就停止匹配,比如:a = 1 AND b = 2 AND c > 3 AND d = 4,如果建立 (a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引,则都可以用到,a,b,d的顺序可以任意调整。

2.等于(=)和in 可以乱序。比如,a = 1 AND b = 2 AND c = 3 建立(a,b,c)索引可以任意顺序,MySQL的查询优化器会帮你优化成索引可以识别的模式。

3.尽量选择区分度高的列作为索引,区分度的公式是 COUNT(DISTINCT col) / COUNT(*)。表示字段不重复的比率,比率越大我们扫描的记录数就越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度是0。可能有人会问,这个比率有什么经验么?使用场景不同,这个值也很难确定,一般需要JOIN的字段我们要求在0.1以上,即平均1条扫描10条记录。

4.索引列不能参与计算,尽量保持列“干净”。比如,FROM_UNIXTIME(create_time) = ‘2016-06-06’ 就不能使用索引,原因很简单,B+树中存储的都是数据表中的字段值,但是进行检索时,需要把所有元素都应用函数才能比较,显然这样的代价太大。所以语句要写成 :create_time = UNIX_TIMESTAMP(‘2016-06-06’)。

5.尽可能的扩展索引,不要新建立索引。比如表中已经有了a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

6.单个多列组合索引和多个单列索引的检索查询效果不同,因为在执行SQL时,MySQL只能使用一个索引,会从多个单列索引中选择一个限制最为严格的索引。

5、索引优化

索引优化的目的还是减少磁盘IO次数。

1.最重要的还是多了解业务的使用场景,包括后续可能拓展的场景

2.根据索引建立的原则建立索引,最多不要超过5个,如果有可能的话把多个业务场景的索引合并

3.写SQL语句的话考虑减少回表次数,查询条件尽量全部是索引字段,能应用覆盖索引的尽量用覆盖索引,

4.通过EXPLAIN查看执行计划,重点关注:key(实际选择的索引)、type(连接类型)、rows(影响行数)

image.png 返回结果解析: image.png 我们重点关注的点如下:

  • 使用全表扫描,性能最差,即type="ALL"
  • 扫描行数过多,即rows>阈值
  • 查询时使用了排序操作,也比较耗时,即Extra包含"Using filesort"
  • 索引类型为index,代表全盘扫描了索引的数据,Extra信息为Using where,代表要搜索的列没有被索引覆盖,需要回表,性能较差。 以上几点都可能造成SQL性能的劣化,是我们需要额外关注的高风险sql。*

5.WHERE条件单表查询,锁定最小返回记录表。这句话的意思是,把查询语句的WHERE都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高

6.索引列排序:MySQL查询只使用一个索引,因此如果WHERE子句中已经使用了索引的话,那么ORDER BY中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下,不要使用排序操作;尽量不要包含多个列的排序,如果需要,最好给这些列也创建组合索引。

7.LIKE语句操作:一般情况下,不建议使用LIKE操作;如果非使用不可,如何使用也是一个研究的课题。LIKE “%aaaaa%”不会使用索引,但是LIKE “aaa%”却可以使用索引。

8.不要在索引列上进行运算:在建立索引的原则中,提到了索引列不能进行运算,这里就不再赘述了。

9.有些时候需要考虑保护好像MYSQL这样的中间件,高并发、大数据量的场景SQL语句应该尽量简单,可以考虑让应用程序做比较多的工作,不要用group by这样的操作。

6、MySQL数据库什么情况下设置了索引但无法使用

1.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)

注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引

2.对于多列索引,不是使用的第一部分,则不会使用索引

3.like查询是以%开头

4.如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引

5.如果mysql估计使用全表扫描要比使用索引快,则不使用索引

7、强制SQL规约

1.【强制】不要使用count(列名)或count(常量)来替代count(),count()就是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。

2.【强制】count(distinct col) 计算该列除NULL之外的不重复数量。注意 count(distinct col1, col2) 如果其中一列全为NULL,那么即使另一列有不同的值,也返回为0。

3.【强制】当某一列的值全是NULL时,count(col)的返回结果为0,但sum(col)的返回结果为NULL,因此使用sum()时需注意NPE问题。

4.【强制】使用ISNULL()来判断是否为NULL值。

5.【强制】对于数据库中表记录的查询和变更,只要涉及多个表,都需要在列名前加表的别名(或表名)进行限定。

6.【强制】在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。

7.【强制】不得使用外键与级联,一切外键概念必须在应用层解决。

8.【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

9.【强制】IDB数据订正(特别是删除或修改记录操作)时,要先select,避免出现误删除,确认无误才能提交执行。

查询优化

  • 减少扫描的行数和返回的行数,只返回需要的数据
  • 复杂查询拆分成多个简单查询,在业务逻辑中做数据关联
  • 大数据量分段处理
  • 关联查询驱动表使用小表
  • 尽量避免排序或者使用索引排序,否则可能产生filesort
  • 尽量避免IN子查询,有些时候MySQL会将外层查询压到子查询中,可以采用关联查询替代
  • COUNT()统计列数时,只统计非空字段
  • 延迟关联,子句查询出对应的ID,外层关联所需字段
  • UNION下推查询条件

UNION查询会创建临时表 关联查询执行的是嵌套循环策略 子查询先将结果存放到临时表(派生表),然后执行嵌套循环