欢迎关注WX公众号:“程序猿补课班”,分享Java相关技术知识,学习经验,面试经验等。小伙伴快来补课吧!
接下来看看mini王的面试过程。。。
正文开始
面试官:说说varchar与char的区别?
面试者mini王:
char是固定长度的,varchar是可变长度,因为变长字段存储空间小,可以节省存储空间,
所以尽可能的使用 varchar。
面试官:varchar(50) 里面的50代表什么?
面试者mini王:
varchar(50)中50是最多存放50个字符,varchar(50)和(200)存储数据所占空间一样,只不过后者在排序时会消耗更多内存。
面试官:那再说说MyISAM和InnoDB的区别
面试者mini王:
mysql-5.1版本之前默认引擎是MyISAM,之后是innoDB
InnoDB支持事物,而MyISAM不支持事物
InnoDB支持行级锁,而MyISAM支持表级锁
InnoDB支持MVCC, 而MyISAM不支持
InnoDB支持外键,而MyISAM不支持
InnoDB不支持全文索引,而MyISAM支持。
面试官:drop、delete与truncate的区别
面试者mini王:
当不再需要该表时,用drop;当仍要保留该表,但要删除所有记录时,用truncate;当要删除部分记录时,用delete,并且可以回滚恢复数据
面试官:一张表,里面有 ID 自增主键,当 insert 了 17 条记录之后,删除了第 15,16,17 条记录,再把 Mysql 重启,再 insert 一条记录,这条记录的 ID 是 18 还是 15 ?
面试者mini王:一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是18;但是如果重启MySQL的话,这条记录的ID是15。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。
但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是18。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。
注:如果在这17条记录里面删除的是中间的几个记录(比如删除的是10,11,12三条记录),重启MySQL数据库后,insert一条记录后,ID都是18。因为内存或者数据库文件存储都是自增主键最大ID
面试官:心想 。。嗯~ 回答的还可以
面试官:什么是脏读,幻读,不可重复读呢?
面试者mini王:
事务A读取到事务B未提交的数据,这就是脏读
两个相同的查询,却返回了不同的数据,这就是不可重复读。
事务A查询数据,另一个并发事务B把数据进行插入/删除操作,并静悄悄地提交,然后事务A再次查询数据,两次读取得到的数据不一样了,这就是幻读。
面试官:union、union all的区别
面试者mini王:
UNION会筛选掉重复的记录,Union All不会去除重复记录;
面试官:来说一说索引吧,索引有哪几种类型?
面试者mini王:
主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。
唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。
全文索引:是目前搜索引擎使用的一种关键技术,对文本的内容进行分词、搜索。
组合索引:多列值组成一个索引,用于组合搜索,效率大于索引合并
面试者mini王:回答的还可以吧 嘿嘿~
面试官:知道聚集索引与非聚集索引的区别吗
面试者mini王:
聚集索引:本身就是按照某一种规则排列的索引。像字典按字母的来查询,因为文章本身就是按照汉字的字母排序的,所以这种按照字母的查询是聚集索引。
非聚集索引:索引不是数据本身的排序的索引。比如按照偏旁查汉字,同一个偏旁,在文章本身顺序相差很多。
一个表中只能拥有一个聚集索引,而非聚集索引一个表可以存在多个。
面试官:那么创建索引有什么原则呢?
面试者mini王:
最左前缀匹配原则
频繁作为查询条件的字段才去创建索引
频繁更新的字段不适合创建索引
索引列不能参与计算,不能有函数操作
优先考虑扩展索引,而不是新建索引,避免不必要的索引
在order by或者group by子句中,创建索引需要注意顺序
区分度低的数据列不适合做索引列(如性别)
定义有外键的数据列一定要建立索引。
对于定义为text、image数据类型的列不要建立索引。
删除不再使用或者很少使用的索引
面试官:索引哪些情况会失效?
面试者mini王:
嗯嗯 !怎么问题一个接着一个呢,感觉掉进去了一个深坑。。。
查询条件包含or,可能导致索引失效
如何字段类型是字符串,where时一定用引号括起来,否则索引失效
like通配符可能导致索引失效。
联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。
在索引列上使用mysql的内置函数,索引失效。
对索引列运算(如,+、-、*、/),索引失效。
索引字段上使用(!= 或者 < >,not in)时,可能会导致索引失效。
索引字段上使用is null, is not null,可能导致索引失效。
左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。
面试官:日常工作中你是怎么优化SQL的?
面试者mini王:
加索引
避免返回不必要的数据
适当分批量进行
优化sql结构
分库分表
读写分离
课外辅导:
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
`select id from t where num=10
union all
select id from t where num=20`
5.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查询也将导致全表扫描:
select id from t where name like '%abc%'
7.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100
应改为:
select id from t where num=100*2
8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)='abc'--name以abc开头的id
应改为:
select id from t where name like 'abc%'
9.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
10.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
11.不要写一些没有意义的查询,如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
create table #t(...)
12.很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
13.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
14.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,
因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
15.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
16.尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,
其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
17.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
18.避免频繁创建和删除临时表,以减少系统表资源的消耗。
19.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
20.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,
以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
21.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
)
面试官:数据库索引的原理,为什么要用 B+树?
面试者mini王:
那为什么不是B树而是B+树呢?
1)B+树非叶子节点上是不存储数据的,仅存储键值,而B树节点中不仅存储键值,也会存储数据。innodb中页的默认大小是16KB,如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少,数据查询的效率也会更快。
2)B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的,链表连着的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。
例如:limit 1000000 加载很慢的话,你是怎么解决的呢?
方案一:如果id是连续的,可以这样,返回上次查询的最大记录(偏移量),再往下limit
select id,name from employee where id>1000000 limit 10.
方案二:在业务允许的情况下限制页数:
建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。
方案三:order by + 索引(id为索引)
select id,name from employee order by id limit 1000000,10
方案四:利用延迟关联或者子查询优化超多分页场景。(先快速定位需要获取的id段,然后再关联)
SELECT a.* FROM employee a, (select id from employee where 条件 LIMIT 1000000,10 ) b where a.id=b.id
面试官:一条sql执行过长的时间,你如何优化,从哪些方面入手?
面试mini王:查看是否涉及多表和子查询,优化Sql结构,如去除冗余字段,是否可拆表等
优化索引结构,看是否可以适当添加索引
数量大的表,可以考虑进行分离/分表(如交易流水表)
数据库主从分离,读写分离
explain分析sql语句,查看执行计划,优化sql
查看mysql执行日志,分析是否有其他方面的问题
面试官:嗯 基本问题还算可以,等回去HR通知你结果哈
面试mini王:好滴 谢谢(这次面试还算ok)
补充知识:
问了下MySQL数据库cpu飙升到500%的话他怎么处理?
如有错漏之处,敬请指正