常见面试题的基础总结(数据库篇)
由于这些内容都是比较早之前进行的整理的,所以有的部分是参考了他人的博文,但是由于是之前找的,所以具体的博文链接找不到了,如果原博主看到这个文章或者有人知道其中部分内容的原博文,请与我联系,我将加上原链接,谢谢
1、为什么要使用索引
- 为了快速查询数据
2、如何创建索引
-
唯一索引
CREATE UNIQUE INDEX 索引名称 ON 表名称 (列名称)
-
简单索引
CREATE INDEX 索引名称 ON 表名称 (列名称)
3、普通索引,唯一索引,主键索引,全文索引,组合索引
- 一个表只能有一个主键索引,可以有多个唯一索引;
- 主键索引一定是唯一索引, 唯一索引不是主键索引;。
- 普通索引:最基本的索引,没有任何限制
- 唯一索引:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。
- 主键索引:它是一种特殊的唯一索引,不允许有空值。
- 全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时好空间。
- 组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。
4、密集索引,稀疏索引
- 密集索引:每个搜索码值都对应一个索引值
- 稀疏索引:只为某些值建立索引
5、什么是最左前缀原则
CREATE TABLE `user2` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL DEFAULT '',
`password` varchar(20) NOT NULL DEFAULT '',
`usertype` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`userid`),
KEY `a_b_c_index` (`username`,`password`,`usertype`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
上表中有一个联合索引,下面开始验证最左匹配原则。
- 当存在username时会使用索引查询:
explain select * from user2 where username = '1' and password = '1';
- 当没有username时,不会使用索引查询:
explain select * from user2 where password = '1';
- 当有username,但顺序乱序时也可以使用索引:
explain select * from user2 where password = '1' and username = '1';
在最左匹配原则中,有如下说明:
- 最左前缀匹配原则,非常重要的原则,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的顺序可以任意调整。 - =和in可以乱序,比如
a = 1 and b = 2 and c = 3
建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式 - 最左前缀的成因也不难理解:就是生成索引是先按照第一个索引,再按照第二个索引。如果只有第二个条件,此时第二个条件的索引是无序的。
6、索引失效的几种情况
- 如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
- 对于多列索引,不是使用的第一部分,则不会使用索引
- like查询以%开头
- 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
- 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
7、主键,复合主键,联合主键
- 主键是能唯一表示一条数据的字段
- 复合主键是多个字段的组合
- 联合主键是多个表之间的通过给的数据表主键然后创建的联合主键
8、常见索引的数据结构
二叉搜索树
B-tree
b±tree
Hash
9、b+树和Hash优缺点
- B+树的磁盘读写代价更低
- B +树的查询效率更加稳定
- B+树更有利于对数据库的扫描
- Hash仅仅能满足“=”, "IN”,
- Hash不能使用范围查询
- Hash无法被用来避免数据的排序操作
- Hash不能利用部分索引键查询
- Hash不能避免表扫描
- Hash遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高
10、b数和b+数区别
- b数每个节点都存储key和data,叶子节点的指针为null
- b+数只有叶子节点存储data,叶子节点包含了这个数的所有键值,叶子节点不存值
11、如何定位慢查询
- 根据慢日志查询SQL语句 使用 show variables like ‘%query%’ 可以将slow_query_log选项开启,同时可以查看慢日志的路径
- 使用Explain关键字,即在普通SQL语句前加上Explain,可通过查看extra项和type项看是否使用到了索引
- 最左匹配原则
12、索引是建立的越多越好吗
- 数据量小不需要索引
- 经常变更同时也需要维护索引,意味着更多的维护成本
- 更多索引以为这更多的空间
13、InnoDB和MyISAM区别以及各自适合场景
- InnoDb数据索引在一个文件中。MyISAM数据与索引为两个文件
- MyISAM默认用的是表级锁,不支持行级锁
- InnoDB默认用的是行级锁,也支持表级锁
- MyISAM适合于频繁执行全表count语句,同时对增删改频率不高,查询频繁,没有事务
- InnoDB适合于增删改查都相当频繁,同时可靠性要求比较高,要求支持事务
14、数据库不同隔离级别下遇到的问题
本问题可参考本博客之前的文章:传送门
15、事务的ACID
- 原子性
- 一致性
- 隔离性
- 持久性
16、数据库的优化
读写分离
- 读写分离从字面意思就可以理解,就是把对数据库的读操作和写操作分离开。读写分离在网站发展初期可以一定程度上缓解读写并发时产生锁的问题,将读写压力分担到多台服务器上,通常用于读远大于写的场景。
- 读写分离的基本原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。单表的数据量限制,当单表数据量到一定条数之后数据库性能会显著下降。数据多了之后,对数据库的读、写就会很多。分库减少单台数据库的压力。
主从复制
- 主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;
- 主数据库一般是实时的业务数据库,从数据库的作用和使用场合一般有几个:
- 一是作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作;
- 二是可在从数据库作备份、数据统计等工作,这样不影响主数据库的性能;
17、InnoDB如何手动设置共享锁和排它锁
- 共享锁也叫读锁,简称S锁,原理:一个事务获取了一个数据行的共享锁,其他事务能获得该行对应的共享锁,但不能获得排他锁,即一个事务在读取一个数据行的时候,其他事务也可以读,但不能对该数据行进行增删改。
- 排他锁也叫写锁,简称x锁,原理:一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁(排他锁或者共享锁),即一个事务在读取一个数据行的时候,其他事务不能对该数据行进行增删改查。
如何设置共享锁和排他锁?
- 设置共享锁:
SELECT ... LOCK IN SHARE MODE;
- 设置排他锁:
SELECT ... FOR UPDATE;
18、redis基础数据结构
redis相关问题可参考之前的一些文章:
-
string:是一个可变的字节数组
-
set name zhangsan
(增加) -
get name
(删除) -
strlen name
(获取长度) -
getrange name 1 10
(获取1-10的字符) -
append name ishahaha
(追加字符,此时name 为 zhangsanis) -
decrby name 100
(name的值减100) -
Incrby name 100
(name的值加100)
-
-
List:是一个列表数据结构,且是双向链表
常见操作:rpop
,rpush
,lpop
,lpush
,llen(长度)
,lrange
,lset name 1 lisi(将list的第二个元素修改成lisi)
,lrem(删除)
-
Hash:等价于HashMap
常见操作:hset(添加一个元素)
,hmset(添加多个元素)
,hget(获取一个元素)
,hmget(获取多个元素)
,hkeys(获取所有键)
,hvals(获取所有值)
,hdel(删除元素)
-
Set:类似于HashSet,所以value指向同一个键。
常见操作:sadd(添加)
,smembers(获取所有value)
,scard(获取长度)
,srandmember(获取随机元素)
,srem(删除元素)
,spop(随机删除元素)
,sismember(判断元素是否存在)
-
Sortset:类似于优先队列set中每一个元素有一个score
常见操作:zadd(添加)
,zcard(获取长度)
,zrem(删除元素)
,zremrangebyrank(根据排名删除)
,zremrangebyscore(根据成绩删除)