# MySQL

1. 索引的实现形式
2. B-Tree索引，Hash索引，全文索引，单值索引、唯一索引、复合索引、聚簇索引、非聚簇索引等等，以及它们各自的特点
2. 常见的优化手段，编码时有哪些要注意的
    1. 不要用select * 
    2. 索引，最左原则，最好用覆盖索引
    3. 建表是注意字段长度，各系统对齐，不浪费字段，不常用的字段及大字段可以考虑单独建一张表（可以减少磁盘IO）
    4. 不要多张表join
    5. 不使用UUID作为主键
3. B树与B+树的区别，与跳表的区别
4. B+树是怎么保持平衡的
5. MyISAM与Innodb的区别
    1. 事务 MyISAM不支持事务
    2. 锁  MyISAM只支持表锁，InnoDB支持行锁
    3. ![image](http://imghub.full-stacker.com/qijunImgs/TOIMG926480219093720N.png)
6. MVCC实现原理
7. 表中只有(id =1 ,a=0)一条数据，下述操作结果是怎么样的


时刻| Session A | Session B
---|---|---
 时刻1|begin </br>select a from test where id = 1; | 
 时刻2|update test set a = a+1 where id = 1</br>(此时这条数据加了行锁，sessionB无法更改，只有sessionA commit后才其他事务才可以修改) | 
 时刻3| | select a from test where id = 1;
 时刻4|  | update test set a = a+1 where id = 1
 时刻5 |select a from test where id = 1; | 
 时刻6|commit; | 
 时刻7 |select a from test where id = 1; | 
 
 8. 常见的分库的方法
    1. range方法，根据时间段分库
        1. 京东接单框架的数据每天分一个表 
    2. hash方法，根据业务字段进行hash
    3. 

9. mysql主从同步是怎么实现的，主从延迟怎么解决
    1. 优化网络
    2. 升级Slave硬件配置
    3. Slave调整参数，关闭binlog，修改innodb_flush_log_at_trx_commit参数值
    4. 升级MySQL版本到5.7，使用并行复制
10. 数据库扩容，怎么迁移数据，迁移数据的注意事项。数据迁移中产生的脏数据怎么里。怎么校验数据的迁移结果
11. 什么场景考虑分库分表，分库分表的缺点
12. MySQL的事务隔离级别
13. MySQL如何解决幻读问题，间隙锁是怎么加的，什么时间加的
14. 索引不适用的条件
	索引列上有函数，不满足最左前缀，使用了不等号，使用了范围查询，值类型不匹配等等
索引的分类

15. 为什么mysql使用b+树而不是红黑树或者hashmap或者跳表
    1. 不使用红黑树是因为：
        1. 在增删改查的过程中，时间复杂度为log2n，而b+是logmN，体现在内存和磁盘的IO上，代价比较大。
        2. 特别是插入的时候，红黑树需要进行节点颜色调整，对于频繁的插入而言，这是一个耗时的过程，而b+树仅仅是页分裂问题。另外从并发交付来说，要么线程不安全，要么加锁虽然线程安全，但是牺牲了效率。
        3. 区间查找而言，b+树的叶子节点带有双向链表，因此比较方便。对于红黑树而言，虽然可以实现，比如通过中序遍历的方式，但是实现起来比较复杂。
    2. 不使用hashmap是因为
        1. 假设瓶颈不在hash数组上（hashmap由数组加链表构成），一方面，对于庞大数据量的链表来说，查找的时间复杂度为O（n）
        2. 另一方面从磁盘IO性能考虑，链表足够长，频繁的io会导致极差的性能
        3. 没有办法进行范围查找
    3. 不使用跳表是因为
        1.  虽然在区间查找上两者不相上下，如果纯粹基于内存工作，那就是redis。两者的主要区别，那就是一个是关系型，另一个是非关系型，redis是基于某个key进行排序构造的，如果像mysql哪样建立二级索引，那么每一个都是“聚簇索引”，得不偿失，维护也麻烦（就是说跳表无法解决索引问题）
        2.  还是数据关系型的问题，虽然说跳表这个结构也可以以Json格式来存储数据库的行数据，但是类似主外键关系、模糊查找等功能，无法提供或者提供起来较为繁琐
        3.  如果考虑到足够大的数据，大到需要使用硬盘的话，内存和磁盘进行io的内容会是什么？是跳表的每一层数据，前几层可能还好，越往下，可能不是一次页交换可以容纳下的，那么跳表在查找上的优势尽失，反观mysql，每次交换出来的非叶子节点都是索引，可查找范围大，io次数少，性能高
16.  为什么redis使用跳表而不是红黑树或者hashmap
    1. 由上面分析可知，红黑树在内存工作效率更高，但是同样基于内存的redis为什么不用红黑树，区别在于红黑树范围查询太费劲，插入元素时进行的节点颜色调整太费解，同样的操作，跳表仅仅需要更新前后下三个指针即可，而且，红黑树这样做来保持平衡带来的查找优势对跳表来说并不明显
    2. 不使用hashmap，也是因为链表的操作太费时，远不如跳表这种链表的折半查找来的快
17. 读写分离
    1. 为什么要读写分离
        1. 扩展读能力
    2. 怎么读写分离
        MySQL原生支持主从复制，主库写数据，写binlog，从库同步主库的数据，向外提供读服务
18. MySQL主从复制的原理
    IO线程读binlog日志（记录了增删改操作），写入从库的relaylog中，从库的SQL线程，见relaylog 写入数据，从库读取binlog 写relay log ，写数据都是串行的
19. 主从延迟相关
     1. 主库的并发越高，延迟就越大
     2. semi-sync 半同步复制   从库写到relay log即返回成功
     3. 主从延迟的解决方式：
        1. 将主库拆分，减少并发，减少延迟
        2. 打开并行复制（并行复制什么？）
        3. 代码层面的处理： 如 写后直接更新，而不要 “写”--> "查"--> "更新"
        4. 如果确实存在写后立即查询的场景，可以强制查“主库”，但这样就失去了读写的分离的意义，不推荐
20. 分库分表中间件
    1. proxy方式的中间件 （有维护成本）
        1. cobar
        2. atlas(360公司开源)
        3. mycat 
    2. client方式的中间件
        1. TDDL
        2. sharding-jdbc (支持分布式事务)
21. 分库分表的方式
    1. range方式， 按时间来分
        1. 优点
        2. 缺点
    2. hash方式： 选定一个键，进行hash
        1. 优点
        2. 缺点
22. 分库分表数据迁移
    1. 停机迁移
    2. 不停机迁移：
        1. 双写： 既写老库也写新库 
23. 数据库动态扩容 
    1. 数据库中间件
    2. 停机扩容：
        1. 从单库单表迁移到多库多表时经常使用
    3. 不停机扩容
        1. 初始设计时就设计大一点，如 32个库，每个库32张表，只扩数据库服务器，不扩表，可以减少代码修改
         路由规则： id%32=库  (id/32)%32=表
24. 分布式id怎么生成
    1. 向全局数据库中生成id（支持的并发低但数据多）
    2. UUID
    3. 获取当前时间，并发高时容易出问题-->改进 时间戳+用户ID+业务含义编码
    4. 雪花算法： 64位 long型ID--》二进制（0|时间戳|机房|机器ID）
    5. 利用redis自增 （jd使用）
