Mysql知识随记

目录

  • SQL语句优化
  • 索引优化
  • 创建临时表的几种情况
  • 乐观锁和悲观锁
    • 悲观锁
    • 乐观锁
    • 悲观锁与乐观锁的应用场景
  • MySQL存储引擎中的MyISAM和InnoDB
  • 分表
    • 表的垂直拆分
    • 表的水平拆分

SQL语句优化

  1. 在where 和 order by 中使用索引字段

  2. where 子句中 避免使用<> !=也不要进行 is null 判断,否则会放弃索引

  3. where 子句中 使用or需要左右均使用索引,否则放弃使用索引

  4. where 子句中 不要再 = 左边进行函数、算术运算或其他表达式运算

  5. 避免使用模糊查询(like %a)

  6. 如果 in 中为连续数值,建议使用between

  7. 避免使用 ‘*’ 应选择需要返回的字段

  8. 有时候使用 exists 代替 in 是一个好的选择:
    select num from a where num in(select num from b)
    用下面的语句替换:
    select num from a where exists(select 1 from b where num=a.num)

索引优化

  1. 索引建立应选择经常作查询选择的字段、经常作表连接的字段以及经常出现在order by、group by、distinct 后面的字段

  2. 索引会提升 select 效率,同时降低 insert 和 update 效率,所以应选择合适字段建立索引

  3. 联合索引最左匹配原则

创建临时表的几种情况

  1. UNION查询;
  2. 用到TEMPTABLE算法或者是UNION查询中的视图;
  3. ORDER BY和GROUP BY的子句不一样时;
  4. 表连接中,ORDER BY的列不是驱动表中的;(指定了联接条件时,满足查询条件的记录行数少的表为[驱动表],未指定联接条件时,行数少的表为[驱动表],多表联合查询时)
  5. DISTINCT查询并且加上ORDER BY时;
  6. SQL中用到SQL_SMALL_RESULT选项时;
  7. FROM中的子查询;
  8. 子查询或者semi-join时创建的表;

乐观锁和悲观锁

悲观锁

悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为所有的操作均会导致并发安全问题,因此要先确保获取锁成功再进行业务操作。通常来讲,在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select … for update时会获取被select中的数据行的行锁,因此其他并发执行的select … for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。   
这里需要特别注意的是,不同的数据库对select… for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,mysql就没有no wait这个选项。另外,mysql还有个问题是: select… for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此,如果在mysql中用悲观锁务必要确定使用了索引,而不是全表扫描。

乐观锁

乐观锁的特点先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过,若未被更新过,则更新成功;否则,失败重试。乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是在需要锁的数据上增加一个版本号或者时间戳,然后按照如下方式实现:
下面展示一些 内联代码片

SELECT data AS old_data, version AS old_version FROM;
//根据获取的数据进行业务操作,得到new_data和new_version
UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
// 乐观锁获取成功,操作完成
} else {
// 乐观锁获取失败,回滚并重试
}

乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对比版本号确认与之前获取的相同,并更新版本号,即可确认这其间没有发生并发的修改。如果更新失败,即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。

悲观锁与乐观锁的应用场景

一般情况下,读多写少更适合用乐观锁,读少写多更适合用悲观锁。乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能。

MySQL存储引擎中的MyISAM和InnoDB

MyISAM:不支持事务,不支持外键,表锁;插入数据时锁定整个表,查行数时无需整表扫描。主索引数据文件和索引文件分离;与主索引无区别。

InnoDB:支持事务,外键,行锁,查表总行数时,全表扫描;主索引的数据文件本身就是索引文件;辅助索引记录主键的值。

MyISAM 和 InnoDB 都是使用B+Tree索引结构。MyISAM 查询速度比 InnoDB 快的原因:

MyISAM 叶节点的data域存放的是数据记录的地址。通过索引可以直接找到数据存储位置(经历1遍B+Tree)

InnoDB 的数据文件本身就是索引文件,叶节点data域保存了完整的数据记录。辅助索引的叶节点data域保存主键,因此在索引数据时首先从辅助索引中拿到 主键,再去主键索引中查找数据(经历2遍B+Tree)

分表

表的垂直拆分

把含有多个列的表拆分成多个表,解决表宽度问题,具体包括以下几种拆分手段:

把不常用的字段单独放在同一个表中
把大字段独立放入一个表中
把经常使用的字段放在一起
优点:拆分后业务清晰,拆分规则明确、系统之间整合或扩展容易、数据维护简单

缺点:出现冗余列,经常需要联表查询

表的水平拆分

表的水平拆分用于解决数据表中数据过大的问题,水平拆分每一个表的结构都是完全一致的。一般地,将数据平分到N张表中的常用方法包括以下两种:

  1. 对ID进行hash运算,如果要拆分成5个表,mod(id,5)取出0~4个值;
  2. 针对不同的hashID将数据存入不同的表中;

表的水平拆分会带来一些问题和挑战,包括跨分区表的数据查询、统计及后台报表的操作等问题,但也带来了一些切实的好处:

  1. 表分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度;
  2. 表中的数据本来就有独立性,例如表中分别记录各个地区的数据或不同时期的数据,特别是有些数据常用,而另外一些数据不常用。
  3. 需要把数据存放到多个数据库中,提高系统的总体可用性。

你可能感兴趣的:(Mysql知识随记)