zoukankan      html  css  js  c++  java
  • [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工程师面试突击(第三季)-- 中华石杉

  • 相关阅读:
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第一题
    fiddler模拟发送post请求
  • 原文地址:https://www.cnblogs.com/fyql/p/12362351.html
Copyright © 2011-2022 走看看