Java面试题专集--MySql索引、B+树、锁
lipiwang 2024-11-21 17:43 5 浏览 0 评论
索引类型
- 主键索引
- 唯一索引
- 普通索引
- 组合索引
- 全文索引
索引采用的数据结构
- B+树
- Hash
索引的匹配方法
- 全值匹配 (3个字段组合索引查3个字段)
- 匹配最左前缀 (3个字段组合索引查2个字段) “最左匹配”原则,存储引擎不能使用范围条件右边的索引列。mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
- 匹配列前缀 (like '赵%')
- 匹配范围值
- 精确匹配某一列,并范围匹配另外一列 (组合索引)
- 只访问索引的查询(本质是覆盖索引)
面试技术名词
- 回表
- 覆盖索引
- 最左匹配(组合索引时)
- 索引下推:有了索引下推优化,可以在有like条件查询的情况下,减少回表次数。对于user_table表,我们现在有(username,age)联合索引 , select * from user_table where username like '张%' and age > 10 如果没有索引下推优化(或称ICP优化),当进行索引查询时,首先根据索引来查找记录,然后再根据where条件来过滤记录;在支持ICP优化后,MySQL会在取出索引的同时,判断是否可以进行where条件过滤再进行索引查询,也就是说提前执行where的部分过滤操作,在某些场景下,可以大大减少回表次数,从而提升整体性能。
常见树的特点
- AVL T ree平衡树,查询性能高,插入性能低,不均衡,所以不合适;
- 红黑树 高度不超2倍、变色,查询、插入性能平衡
- B-树,是一个够扁平的树,树的深底浅减少遍历树的IO次数,B-树一个父节点有多个子节点,合适。
B 树介绍
B 树是为了磁盘存储设备而设计的一种多叉平衡查找树。(相对于二叉,B树每个内结点有多个分支,即多叉)
首先我们介绍一下一棵 m 阶B-tree的特性
m 阶的定义:一个节点能拥有的最大子节点数来表示这颗树的阶数
举个例子:如果一个节点最多有 n 个key,那么这个节点最多就会有 n+1 个子节点,这棵树就叫做 n+1(m=n+1)阶树;
B-树与B+树的区别
- B-树可以在非叶子结点命中,越靠近根节点的记录查找时间越快,只要找到关键字即可确定记录的存在; B+树只有达到叶子结点才命中;
- B-树的关键字和记录是放在一起的,叶子节点可以看作外部节点,不包含任何信息;B+树的非叶子节点中只有关键字和指向下一个节点的索引,数据只放在叶子节点中。
- B+树:叶子节点,有指向临近叶子节点的指针,方便顺序遍历, 范围查找。
- B+树:所有关键字都在叶子结点出现,叶子结点相当于是存储(关键字)数据的数据层;
InnoDB索引与MyISAM索引区别
- 第一个重大区别是,MyISAM索引文件和数据文件是分离的; InnoDB的数据文件本身就是索引文件, InnoDB索引B+树的叶节点data域保存了完整的数据记录。 这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。
- 第二个与MyISAM索引的不同是InnoDB的辅助索引data域,存储记录主键,而不是地址。
使用InnoDB引擎要注意的点
- 因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。使用短的数据类型。
- 在InnoDB中不要用非单调的字段作为主键。因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。
为什么说B+树比B树更适合数据库索引?
1、 B+树的磁盘读写代价更低:操作系统按磁盘快预读数据,B+树的内部节点更小,一个磁盘盘块中可容纳的内部节点更多,IO次数会更少。B+树更加扁平遍历树时IO次数少。
2、B+树的查询效率更加稳定:关键字的查找必须走一条从根结点到叶子结点的路径,路径长度相同,使每一次数据的查询效率相同。
3、B+树更加适合做顺序遍历、区间查询:由于B+树的数据都存储在叶子结点中,有指针指向临近叶子节点,方便顺序扫表,适合做区间查询。
但是B树因为其分支结点同样存储着数据,需要进行一次中序遍历按序来扫表。所以B+树更加适合区间查询的情况,所以通常B+树用于数据库索引。
索引设计的原则
- 适合加索引的列是出现在where条件中的列,或者join子句中指定的列;
- 优先使用短的列做索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间;
- 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。
- 基数较大的列,如比性别列,只有0与1,索引效果很差,没有必要在此列建立索引;
- 根据where子句来分析,合理创建组合索引,使用“最左匹配”原则,发挥“覆盖索引”特点,减少“回表”;
- 根据where子句来分析,合理创建组合索引,使用“索引下推”思路,可以在有like条件查询的情况下,减少回表次数。
- 使用 explain命令,查看执行计划,分析索引使用情况并进行优化。
索引优化具体事项
- 不要在索引列上做任何计算,比如使用函数、自动或手动进行类型转换,都会导致索引失效,从而进行全表扫描。
- mysql在使用不等于(!=或者<>)的时候无法使用索引,会导致全表扫描。
- mysql where条件中避免使用,is null,is not null 因为无法使用索引。
- mysql where条件,like以通配符开头(like '%aaa')索引失效会变成全表扫描操作。
- 减少查询返回的列的数量,可减少传输的数据量 。减少select * 语句,发挥“覆盖索引”的优势(只访问索引的查询(索引列包含查询列))
- innodb引擎,使用自增字段作为主键,避免B+树索引的分裂 。
- 字符串不加单引号会导致索引失效,更准确的说是类型不一致会导致失效。比如字段email是字符串类型的,使用WHERE email=99999 则会导致失败,应该改为WHERE email='99999'。
- 在查询条件中使用OR连接多个条件会导致索引失效,除非OR链接的每个条件都加上索引,这时应该改为两次查询,然后用UNION ALL连接起来。
Mysql 讲一下 页锁、行锁、表锁
最全MySQL锁讲解:页锁、共享锁、行锁、表锁、悲观锁、乐观锁
- 表级锁:开销小,加锁快;不会出现死锁(因为MyISAM会一次性获得SQL所需的全部锁);锁定粒度大,发生锁冲突的概率最高,并发度最低。
- 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
- 页锁:是给一页数据加锁,开销和加锁速度介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般。
Mysql 悲观锁 和 乐观锁
(1)悲观锁:顾名思义就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
(2)乐观锁: 顾名思义就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
(3)悲观锁 和 乐观锁的区别:
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
Mysql 什么时候使用表锁
对于InnoDB引擎,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁。
- 第一种情况是:事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。
- 第二种情况是:事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。
当然,应用中这两种事务不能太多,否则,就应该考虑使用MyISAM引擎了。
Mysql 表锁和行锁应用场景
- 表级锁使用于,并发性不高,以查询为主,少量更新的应用,比如小型的web应用;
- 行级锁适用于,高并发环境下,对事务完整性要求较高的系统,如在线事务处理系统;
Mysql的四种隔离级别
Read Uncommitted(读取到未提交内容)(会发生:脏读、不可重复读、幻读)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
Read Committed(读取提交内容 或 不可重复读)(会发生:不可重复读、幻读)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
Repeatable Read(可重复读)(会发生:幻读)(是mysql的默认隔离级别。 )
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
Serializable(可串行化)(会发生:无)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
说一下Mysql 的MVCC
https://zhuanlan.zhihu.com/p/75737955
多版本并发控制(MVCC,Multiversion Concurrency Control)
MVCC使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能。
MVCC工作过程
InnoDB的MVCC,是通过在每行纪录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存了行的过期时间(或删除时间),当然存储的并不是实际的时间值,而是系统版本号。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行纪录的版本号进行比较。在REPEATABLE READ隔离级别下,MVCC具体的操作如下:
undo log
在不考虑redo log 的情况下利用undo log工作的简化过程为:
1)为了保证数据的持久性数据要在事务提交之前持久化;
2)undo log的持久化必须在在数据持久化之前,这样才能保证系统崩溃时,可以用undo log来回滚事务;
MVCC优缺点
MVCC在大多数情况下代替了行锁,实现了对读的非阻塞,读不加锁,读写不冲突。缺点是每行记录都需要额外的存储空间,需要做更多的行维护和检查工作。
1.MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read)。
2.MVCC主要作用于事务性的,有行锁控制的数据库模型。
- 上一篇:Java基础入门(运算符)
- 下一篇:好程序员Java培训分享For循环详解
相关推荐
- linux实例之设置时区的方式有哪些
-
linux系统下的时间管理是一个复杂但精细的功能,而时区又是时间管理非常重要的一个辅助功能。时区解决了本地时间和UTC时间的差异,从而确保了linux系统下时间戳和时间的准确性和一致性。比如文件的时间...
- Linux set命令用法(linux cp命令的用法)
-
Linux中的set命令用于设置或显示系统环境变量。1.设置环境变量:-setVAR=value:设置环境变量VAR的值为value。-exportVAR:将已设置的环境变量VAR导出,使其...
- python环境怎么搭建?小白看完就会!简简单单
-
很多小伙伴安装了python不会搭建环境,看完这个你就会了Python可应用于多平台包括Linux和MacOSX。你可以通过终端窗口输入"python"命令来查看本地是否...
- Linux环境下如何设置多个交叉编译工具链?
-
常见的Linux操作系统都可以通过包管理器安装交叉编译工具链,比如Ubuntu环境下使用如下命令安装gcc交叉编译器:sudoapt-getinstallgcc-arm-linux-gnueab...
- JMeter环境变量配置技巧与注意事项
-
通过给JMeter配置环境变量,可以快捷的打开JMeter:打开终端。执行jmeter。配置环境变量的方法如下。Mac和Linux系统在~/.bashrc中加如下内容:export...
- C/C++|头文件、源文件分开写的源起及作用
-
1C/C++编译模式通常,在一个C++程序中,只包含两类文件——.cpp文件和.h文件。其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码;而.h文件则被称...
- linux中内部变量,环境变量,用户变量的区别
-
unixshell的变量分类在Shell中有三种变量:内部变量,环境变量,用户变量。内部变量:系统提供,不用定义,不能修改环境变量:系统提供,不用定义,可以修改,可以利用export将用户变量转为环...
- 在Linux中输入一行命令后究竟发生了什么?
-
Linux,这个开源的操作系统巨人,以其强大的命令行界面而闻名。无论你是初学者还是经验丰富的系统管理员,理解在Linux终端输入一条命令并按下回车后发生的事情,都是掌握Linux核心的关键。从表面上看...
- Nodejs安装、配置与快速入门(node. js安装)
-
Nodejs是现代JavaScript语言产生革命性变化的一个主要框架,它使得JavaScript从一门浏览器语言成为可以在服务器端运行、开发各种各样应用的通用语言。在不同的平台下,Nodejs的安装...
- Ollama使用指南【超全版】(olaplex使用方法图解)
-
一、Ollama快速入门Ollama是一个用于在本地运行大型语言模型的工具,下面将介绍如何在不同操作系统上安装和使用Ollama。官网:https://ollama.comGithub:http...
- linux移植(linux移植lvgl)
-
1uboot移植l移植linux之前需要先移植一个bootlader代码,主要用于启动linux内核,lLinux系统包括u-boot、内核、根文件系统(rootfs)l引导程序的主要作用将...
- Linux日常小技巧参数优化(linux参数调优)
-
Linux系统参数优化可以让系统更加稳定、高效、安全,提高系统的性能和使用体验。下面列出一些常见的Linux系统参数优化示例,包括修改默认配置、网络等多方面。1.修改默认配置1.1修改默认编辑器默...
- Linux系统编程—条件变量(linux 条件变量开销)
-
条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等...
- 面试题-Linux系统优化进阶学习(linux系统的优化)
-
一.基础必备优化:1.关闭SElinux2.FirewalldCenetOS7Iptables(C6)安全组(阿里云)3.网络管理服务||NetworkManager|network...
- 嵌入式Linux开发教程:Linux Shell
-
本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)