MySql教程

MySQL知识点

本文主要是介绍MySQL知识点,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1.事务数据库三范式
    (1)列不可再分
    (2)依赖主键
    (3)属性不依赖其他非主属性: 原表:学号-姓名-院校编码-院校名称,应拆分为表1 学号-姓名 & 表2 院校编码-院校名称

2.MyISAM与InnoDB的区别
    (1)是否支持行级锁: MyISAM表级锁,InnoDB行级锁
    (2)是否支持事务:MyISAM不支持,InnoDB支持
    (3)是否支持外键:MyISAM不支持,InnoDB支持
    (4)是否支持异常崩溃后的安全恢复:MyISAM不支持,InnoDB支持
    (5)是否支持MVCC:MyISAM不支持,InnoDB支持

3.InnoDB锁算法
    (1)Record lock:行锁
    (2)Gap lock: 间隙锁,锁定一个范围,不包括记录本身
        ①【什么是间隙锁】当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(GAP Lock)。 
        ②【危害】因为Query执行过程中通过过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大的危害
    (3)Next-key lock: record+gap 临健锁,锁定一个范围,包括记录本身

4.查询缓存
    mysql可以通过query_cache_type=1设置查询缓存,但8.0版本移除,不实用。

5.事务的四大特征ACID
    (1)原子性
    (2)一致性
    (3)隔离性
    (4)持久性

6.并发带来的事务问题
 说法一
    (1)脏读:读到另一个事务未提交的信息(同一行),如查询用户名,小明,但小明被其他事务改成了小玲,但事务未提交,读到小玲是错误的
    (2)丢失修改:两个事务都在修改用户名, 事务1 小明改小红,事务2 小明改小绿,最终第一个事务提交的被第二个事务覆盖
    (3)不可重复读:一个事务两次读取到的内容不一致
    (4)幻读:由于其他事务对数据进行增删,使得事务多次读取到的行数不一致

 说法二
    (1)更新丢失(Lost Update)-----相当于svn中的版本覆盖,A跟B更改了同一文件,A覆盖了B的记录
    (2)脏读(Dirty Reads)-----事务A读取到了事务B已修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求
    (3)不可重复读(Non-Repeatable Reads) -----事务A读取到了事务B已经提交的修改数据,不符合隔离性
    (4)幻读(Phantom Reads) -----事务A读取到了事务B提交的新增数据,不符合隔离性

7.事务隔离级别
    (1)读未提交
    (2)读已提交
    (3)可以重复读
    (4)串行

8.索引设计规范
    (1)限制单张表索引数量,建议单表索引不超过5个。
    (2)每个InnoBD表都应该有主键
    (3)建索引字段建议
    (4)出现在select update delete语句中where从句中的列
    (5)包含order by、group by、distinct中的字段
    (6)通常多个字段最后建立联合索引,而不是每个字段都建索引
    (7)join的关联列
    (8)索引列的顺序
    (9)区分度高、字段长度小、使用频繁的放在最左测

9.高效利用索引
    (1)频繁查询的有限考虑使用覆盖索引
    (2)避免数据库进行二次查询,因为二级索引在叶子节点存的是主键信息,通过二级索引检索需要找到主键再进行二次查询。索引覆盖避免回表
    (3)避免使用外键
    (4)避免数据类型的隐式转换, 如select * from abc where id="1"; id是int类型的用了字符
    (5)充分使用已存在的索引,如果避免使用双%,联合索引范围字段放在最后,使用not exist优化not in
    (6)select 具体字段替换select *
    (7)使用连表优化子查询
    (8)避免连表过多
    (9)禁止sql rand()进行随机排序

10.不应该建索引的情况
    (1)表的记录太少了
    (2)经常增删改的表
    (3)where条件里用不到的字段
    (4)区分度不大的字段,建立索引效果太差
    (5)数据库操作规范
    (6)超百万的数据需要分批执行,修改数据要指定范围(binlog row格式会产生大量日志),主从延迟的主要原因:避免产生大事务,锁表阻塞
    (7)避免大表修改,修改前移除约束
    (8)禁止程序使用super权限

11.索引优缺点
    (1)优点:加快检索速度,作为数据约束条件(唯一索引)
    (2)缺点:创建、修改、删除需要维护索引,增加开销;需要物理空间

12.hash索引
    (1)通过key哈希算法计算value的index,找到数据位置。如果hash冲突通常使用链地址法,拉链存储。
    (2)但冲突不是hash的最大缺陷,最大的是hash索引不支持顺序和范围查询。
    (3)所以哈希表这种结构适用于只有等值查询的场景

13.B树&B+树 
 解析
    (1)B树全称多路平衡查找树,B+是B树的一种变体。
    (2)二叉树的特点:左节点小于父节点,右节点大于父节点。时间复杂度是O(logN),为了维持O(logN)的查询复杂度就需要对树进行平衡。
    (3)B树是可以多个子节点,子节点大小从左到右依次递增。二叉树虽然搜索效率是最高的,但数据库存储并不使用二叉树,因为索引不止存在存在内存,还要写在磁盘。二叉树搜索深度大,IO次数高。
    (4)每个节点一个磁盘块,磁盘块包含数据 和 指针
 差异
    (1)节点存放数据: B树所有节点都存放数据,而B+树只有也只节点存放key和data,其他内节点只会存放key(因为节点只存放放关键字所以单个磁盘块可以容纳的关键字树越多)
    (2)叶子节点: B树的叶子节点都是独立的,而B+树有个一个引用链表指向它相邻的叶子节点
    (3)检索过程: B树对每个的关键字做二分查找,可能不用到达叶子节点就检索结束,检索效率不稳定。但B+树需要从跟节点检索到叶子节点。

14.MyISAM与InnoDB的B+树索引区别
    (1)虽然MyISAM与InnoDB的默认索引都是B+树,但MyISAM是索引文件和数据文件分离的,索引叶子节点data域是数据的地址。
    (2)而B+树上data域是完成的数据记录。
    (3)InnoDB表数据文件本身就是主索引,所以这被称为“聚族索引”。
    (4)InnoDB辅助索引查找是找到的,则是取到主键再走一边主索引,和MyISAM的数据地址有差别

15.聚族索引和非聚族索引的区别
    (1)聚族索引:将数据存储和索引放到一块,找到索引就找到数据
    (2)非聚族索引:将数据存储和索引分开结构,索引结构的叶子节点指向了数据对应行,MyISAN通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘响应的数据,这也就是为什么索引在key buffer命中是,速度慢的原因

16.非聚族索引查询一定回调查询吗?
    不是,索引覆盖可以避免回表

17.redo log
    重做日志,让MySQL拥有崩溃恢复能力。
    MySQL以页为单位,当查询一条数据时会把整页查询出来放在Buffer Pool中,后续查询都从缓存池里查,没有再去硬盘查询,以减少IO操作。
    更新数据逻辑也是先更新Buffer Pool然后记录到日志缓存(redo log buffer)接着刷盘。
    刷盘时机策略配置innodb_flush_log_at_trx_commit
        0:每次提交事物不刷 (宕机有可能丢失一秒数据)
        1:每次提交事物都刷(默认)
        2:每次提交只把redo log buffer写入page cache(宕机有可能丢失一秒数据)
    innodb有一个后台进程每隔1秒就把redo log buffer写入page cache然后调用fsync刷盘,也就是没有提交的事物都有可能刷盘
    redo log buffer占用空间达到innodb_log_buffer_size一半时也会主动刷盘

18.binlog
    逻辑日志,用于主从备份
    记录格式:statement、row、mixed
        statement记录执行sql语句,但有个问题,update_time=now(), 主从机器时间不一致可能存在差异。
        row包含修改的记录,update_time=now()会转化为具体的时间。但会产生大量的日志,占用大量的空间和io
        mixed是前两种组合,他会判断时候有可能引起数据不一致,会的使用row,否则使用statement。
    每次事物开始执行就会写入binlog cache,提交是再把binlog cache写入binlog文件。
    刷盘时机可以sync_binlog控制,默认是0,由系统决定什么时候进行fsync。安全期间可以设置为1每次提交就进行fsync。折中的方式可以这是N,标识累计多少个事物才进行fsync,但风险就是宕机会丢失N个事物的日志。

19.两段提交
    redo log和binlog是两份日志,redo log可以不停的写入,但binlog只有事物提交才写入。假若出现redo log写入了,binlog未写入出现崩溃,那binlog就少了一份日志最终出现主从数据不一致。
    因为redo log采用两段提交,prepare和commit两个阶段。当发现redo log处于prepare且没有binlog就回滚事物

20.undo log
    回滚日志,回滚日志会先于数据持久化到磁盘,保证宕机能回滚之前未完成的事

21.MVCC
    (1)一致性非锁定读,通常做法是加一个版本号或者时间戳,查询时,将当前可见版本和对应版本比较,如果记录版本小于当前版本则表示可见
    (2)多版本控制是对非锁定读的实现,所以正在执行delete或update操作,不会等待行解锁,而是引擎去读行的一个快照数据。
    (3)锁定读,执行select ... for update等读取最新的版本

22.InnoDB对MVCC的实现
    MVCC依赖:隐藏字段、Read View、undo log。
    通过DB_TRX_ID和Read View来判断数据的可见性,如不可见从undo log找到历史版本。
    行更新的过程
    InnoDB为每行记录都实现了三个隐藏字段:
        隐藏的ID
        6字节的事务ID(DB_TRX_ID)
        7字节的回滚指针(DB_ROLL_PTR)
    数据库新增一条数据,该条数据三个隐藏字段,只有ID有值
    T1修改该条数据,开启事务,记录read_view
        排它锁锁定该行数据
        记录redo log
        将该行数据写入undo log
        将修改值写入该条数据,填写事务Id,根据undo log记录位置填写回滚指针
    T2修改该条数据,开启事务,记录read_view
        排它锁锁定该行数据
        记录redo log
        将该行数据写入undo log
        将修改值写入该条数据,填写事务Id,通过回滚指针将undo log 的两条记录连接起来(版本链)
        事务提交,记录read_view
    正常提交
    如果触发回滚,需要根据回滚指针找到undo log对应记录进行回滚
    注意:
        InnoDB中存在purge线程,它负责查询,并清理那些无效的undo log。
        上述过程描述的是UPDATE事务的过程,当INSERT时,原始的数据并不存在,所以在回滚时把insert丢弃即可
    参考:https://juejin.cn/post/7032993523435569165

23.explain分析sql性能
    https://www.www.zyiz.net/i/l/?n=18&i=blog/1377406/201906/1377406-20190623203933498-1015252086.png
    id select_type table type possible_keys key key_len ref rows extra

24.MySQL 字符编码集中有两套 UTF-8 编码实现:
    (1)utf8 : utf8编码只支持1-3个字节 。 在 utf8 编码中,中文是占 3 个字节,其他数字、英文、符号占一个字节。但 emoji 符号占 4 个字节,一些较复杂的文字、繁体字也是 4 个字节。
    (2)utf8mb4 : UTF-8 的完整实现,正版!最多支持使用 4 个字节表示字符,因此,可以用来存储 emoji 符号。

25.Datetime 和 Timestamp 之间抉择
    (1)DateTime 类型是没有时区信息的(时区无关) ,DateTime 类型保存的时间都是当前会话所设置的时区对应的时间。这样就会有什么问题呢?当你的时区更换之后,比如你的服务器更换地址或者更换客户端连接时区设置的话,就会导致你从数据库中读出的时间错误。不要小看这个问题,很多系统就是因为这个问题闹出了很多笑话。
    (2)Timestamp 和时区有关。Timestamp 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间,说简单点就是在不同时区,查询到同一个条记录此字段的值会不一样。
    (3)DateTime 类型耗费空间更大:Timestamp 只需要使用 4 个字节的存储空间,但是 DateTime 需要耗费 8 个字节的存储空间。但是,这样同样造成了一个问题,Timestamp 表示的时间范围更小。
    DateTime :1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
    Timestamp: 1970-01-01 00:00:01 ~ 2037-12-31 23:59:59

这篇关于MySQL知识点的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!