• [Java复习] 面试突击


    MySQL 几大部分存储引擎、索引、事务、锁

    MySQL的MyISAM和InnoDB存储引擎的区别是啥?

    myisam,不支持事务,不支持外键约束,索引文件和数据文件分开,这样在内存里可以缓存更多的索引,对查询的性能会更好,适用于那种少量的插入,大量查询的场景。

    innodb,主要特点就是支持事务,走聚簇索引,强制要求有主键,支持外键约束,高并发、大数据量、高可用等相关成熟的数据库架构,分库分表、读写分离、主备切换,全部都可以基于innodb存储引擎。

    聊聊MySQL的索引实现原理?各种索引你们平时都怎么用的?

    • MySQL索引的原理和数据结构能介绍一下吗?
    • b+树和b-树有什么区别?
    • Myisam和Innodb存储引擎的索引实现?
    • MySQL聚簇索引和非聚簇索引的区别是什么?
    • 他们分别是如何存储的?
    • 使用MySQL索引都有哪些原则?
    • MySQL复合索引如何使用?

    先说什么索引?

    索引就是用一个数据结构组织某一个列数据,然后根据这一列数据查询时,不用全表扫描,根据特定数据结构找到那一列的值,然后找到对应行的物理地址。

    先说b-树,画图如下:

    查找时,从根节点开始二分查找。

    b+树是b-树的变形,不一样的地方:

    B-和B+树区别:

    1. B+树只有叶子节点存储数据,其他中间节点只有索引没有数据,同样的大小的磁盘页可以容纳更多的节点元素。相同数量下,B+树更“矮胖”,查询IO次数更少

    2. B+树查询必须查找叶子节点,B+树查询更稳定(并不慢)。B-树查询性能不稳定,最好只查根节点,最坏查到叶子节点。

    3. B+树范围查询更简便。B+树中序遍历要简单得多

    Myisam和Innodb存储引擎的索引实现?

    myisam的索引中,每个叶子节点的data存放的是数据行的物理地址,每行对应一个物理地址。数据文件单独存放一个文件。最大特点是数据文件和索引文件是分开的。

    innodb的数据文件本身就是索引文件,必须有主键,会根据主键建立一个默认索引,叫聚簇索引

    innodb下,对某个非主键字段创建索引,那么最后那个叶子节点的值就是主键的值,再用主键的值到聚簇索引里查找到数据,叫回表

    innodb,建议统一用auto_increment自增值作为主键,可以保持聚簇索引直接加记录,不用修改原来b+树的结构,浪费时间。

    索引常见使用规则?

    比如product表,创建索引:

    create index (shop_id, product_id, gmt_create)

      1. 全列匹配

          where条件正好用到这3个字段,就用到联合索引

      2. 最左前缀匹配

          SQL里,正好用到联合索引最左边的一个或几个列表。

      3. 最左前缀匹配,但中间某个值没有匹配

          如果sql用了联合索引第一列和第三列,会按照第一列在索引里找,找完后对结果集根据第三列做全表扫描,不会走第三列的索引了。

      4. 前缀匹配

          如果不是等值,或比如=, >, <=等操作,而是Like操作。则只有Like ‘xx%’ (%在最后)这种才能用上索引。

      5. 范围匹配

          只有符号最左前缀的列的范围才用到索引,范围之后的列用不到索引。

          比如: select * from product where shop_id >= 1 and product_id = 1;

          这里就只用到shop_id索引。

      6. 包含函数

         对某个列用了函数,则该列不走索引。

    索引缺点以及使用注意?

        常见缺点:增加磁盘消耗,占用磁盘文件,同时高并发频繁插入和修改索引,会导致性能损耗。

        使用注意:1. 尽量创建少的索引,一个表,两三个。

                           2. 一个字段的值几乎都不太一样的,比如id,这样用索引效果最好。

    小结:

        互联网系统中,一般尽量降低SQL复杂度,用简单的主键索引(聚簇索引)+少数联合索引,

        可以覆盖一个表的所有SQL查询,更复杂的业务逻辑,应该放在Java代码里实现。

        SQL越简单,后面迁移,分库分表,读写分离的成本更低,减少对SQL的改造。

        MySQL最好用在在线及时存储,不要用于计算(Join, 子查询,函数等等)。高并发场景下,计算放在Java内存里

    说说事务的几个特性是啥?有哪几种隔离级别?

    特性:ACid

    原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

    隔离级别:

      1. 读未提交

           事务A把id=1, name=张三修改为李四,但是还未提交,这时事务B已经看到id=1的name为李四了。

      2. 读已提交(不可重复读)

          事务A把id=1, name=张三修改为李四,但是还未提交。事务B第一次读,读到是张三,看不见李四。

          紧接着事务A提交了事务,事务A在第二次读的时候,读到的是修改后的李四。

          这个也叫不可重复读,就是所谓一个事务内对一个数据的两次读,可能读到不一样的值。

      3. 可重复读

          无论事务A什么时候把张三修改为李四,事务B不管什么时刻读到值,都是事务B刚开启时读到的值。事务开启后对一行读取的值都是一样的。

          幻读(不是隔离级别):事务A第一次查询所有数据,就一行id=1。后面事务B插入一行数据id=2,事务A查询时发现2条数据,感觉发生幻觉。

                                                  针对数据件数发生变化。

       4. 串行化

          事务A运行期间,事务B不允许运行。事务A提交完事务后,事务B才开始运行。串行化是为了解决幻读。

    MySQL是怎么实现可重复读的?

        MySQL是通过MVCC机制来实现的,就是多版本并发控制(Multi-Version Concurrency Control)。

        Innodb存储引擎会在每行数据最后增加两个隐藏列

        一个保证行的创建时间,一个保存行的删除时间,但这里存放的不是时间,是事务id,事务id是mysql自己维护的自增,全局唯一。

    举例1:
      id name   创建事务id   删除事务id
      1 张三     101      空
       

        事务id=101的事务查询id=1的这一行,一定能找到创建事务id<=当前事务id的一行。
        当事务id=102把id=1的一行删除了,这时id=1的行的删除事务id设置为102.

    id name   创建事务id   删除事务id
    1  张三     101      102


        事务id=101的事务,再次查询id=1的行,仍然能查到。因为创建事务id<=当前事务id,且当前事务id<删掉事务id。

    举例2:(同一行被修改)
    id   name   创建事务id   删除事务id
    2  李四     201      空
    2  王五     202      空

          事务201创建了id=2的数据,事务202修改了id=2的数据,把name修改为王五,这时候事务201仍然可以查询到创建事务id<=当前事务id的数据,

          查不到比自己创建事务id大的记录。


    MySQL就是通过MVCC实现可重复读,事务可以读取该事务启动时创建事务id的记录,读不到后面事务的版本。

    说说MySQL数据库锁的实现原理吗?如果死锁了咋办?

    数据库锁有哪些类型?锁如何实现的?MySQL行级锁有哪两种?一定会锁指定行吗?为什么?

    悲观锁和乐观锁是什么?使用场景是什么?

    MySQL的死锁原理以及如何定位和解决?

    1. MySQL锁

    锁类型:表锁行锁页锁

      myisam一般加表锁,查询时,默认加共享锁,也就是表读锁,别人可以查,但不能写;

      myisam写的时候,加表独占锁,也就是表写锁,别人不能读也不能写。现在用的很少。

     

      innodb的行锁分共享锁(S)和排他锁(X)。

      共享锁,多个事务可以加共享锁读同一行数据,但别的事务不能写这行数据;

      排他锁,一个事务可以写这行数据,别的事务只能读不能写。

      innodb表锁,分成意向共享锁,就是加共享行锁的时候,必须先加这个共享表锁;

       还有一个意向排他锁,给某行加排他锁的时候,必须先给表加排他锁。这个表锁,是innodb引擎自动加的。

       insert、update、delete时,innodb会自动为这一行加行级的排他锁。

       select时,innodb啥锁都不加,默认实现可重复读,MVCC机制,所有多个事务随便读一个数据,不会有冲突,大家读的是自己的快照,不涉及锁。

      手动加共享锁

    select * from table where id=1 lock in share mode; //id=1这行加了共享锁,其他事务不能修改

      手动加排他锁(悲观锁)

    select * from table where id=1 for update; //id=1这行加了排他锁,表示该事务准备修改,其他事务被卡住等待。慎用!线上一般不用,容易出问题。

      乐观锁:

    select id, name, version from table where id = 1;
    
    update table set name=’new name’, version = version + 1 where id = 1 and version = 1;

      每次修改比较这条数据和之前查出的数据版本号是否一致,一致就修改并且版本号+1,否则就不更新。

      乐观锁可以提高并发访问的效率,但是如果出现了冲突只能向上抛出,然后重来一遍;悲观锁可以避免冲突的发生,但是会降低效率。 

     高并发场景用乐观锁!

      死锁:

        事务A,B对自己的资源持有锁的同时,又要去请求对方持有的锁,结果谁也拿不到锁,导致死锁。

        死锁排查,查看死锁日志,找到对应的sql,找到代码,具体判断为什么死锁。

    MySQL的SQL调优一般都有哪些手段?你们一般怎么做?

      1. SQL慢,一般就是没有用索引。看执行计划,有没有走索引。

    explain select * from table
    
    table|type|possible_keys|key|key_len|ref|rows|extra

    table: 哪个表

    type: 类型  all:全部扫描  const:读常量,最多一条记录匹配  eq_ref:走主键,一般最多一条记录  index:扫描全部索引  range: 扫描部分索引  possible_keys: 显示可能使用的索引

    key: 实际使用的索引

    key_len: 使用索引的长度

    ref: 联合索引哪一列被用到

    rows: 一共扫描和返回了多少行

    extra: using filesort:需要额外进行排序, using temporary: mysql构建了临时表,比如排序的时候 using where:就是对索引扫描出来的数据再次根据where来过滤出结果

    参考资料:

    互联网Java工程师面试突击(第三季)-- 中华石杉

  • 相关阅读:
    【LabVIEW】多列列表框使用汇总
    【LabVIEW】数据类型 汇总
    U-BOOT移植 前准备
    linux 的 输入子系统 与 平台设备系统个人理解
    关于内核编译的理解
    关于 内核编译make menuconfig 不能使用的解决
    函数式接口的使用 (Function、Predicate、Supplier、Consumer)
    获取单列集合,双列集合,数组的Stream流对象以及简单操作
    多线程的创建、匿名内部类方式创建线程、定义、调度步骤
    异常类的使用
  • 原文地址:https://www.cnblogs.com/fyql/p/12362351.html
Copyright © 2020-2023  润新知