常见数据库优化面试题
Posted coderyeah
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常见数据库优化面试题相关的知识,希望对你有一定的参考价值。
常见数据库面试题
一.在项目中如何定位慢查询
- 通过 druid 连接池的内置监控来定位慢 SQL。
- 通过 mysql 的慢查询日志查看慢 SQL。
- 通过 show processlist,查看当前数据库 SQL 执行情况来定位慢 SQL。
二.如何查看sql语句索引命中情况
在 SQL 语句前加上 explain,结果中的 key 就是实际用到的索引
三.说说数据库锁表的场景和解决方法
-
产生场景
锁表通常发生在 DML( insert 、update 、delete )语句中,例如:程序 A 对 A 表的 a 数据 进行修改,修改过程中产生错误,没有 commit 也没有 rollback ,这个时候程序 B 对 A 表的 a 数据进行修改,会产生资源正忙的异常,也就是锁表。
DDL也会引发锁表,例如在 MySql 操作一张大表,利用 alter 语句修改或新增字段的时候,恰巧有一个长事务(包括读)在操作此表,会触发修改等待,造成锁表。
-
原因
当多个事务处理对多个资源同时访问时,若双方已锁定一部分资源但也都需要对方已锁定的资源时,无法在有限的时间内完全获得所需的资源,就会处于无限的等待状态,从而造成其对资源需求的死锁,导致锁表。
-
MySQL解决办法
-
执行SQL
select * from information_schema.processlist where command not in ('Sleep') ORDER BY time desc
-
sql 已经按照阻塞时长从大到小排序,找到耗时长的记录 id ,kill 即可:
kill pid
-
四.truncate和delete的区别
1.delete是DML语句,truncate是DDL语句;
2.delete后面可以有where条件,truncate后面不能加where条件;
3.delete操作后,事务提交后才会生效,truncate操作后立即生效,所以truncate要比delete得执行效率高(数据量大的话就比较明显了);
4.delete操作后,是按行删除,原数据会放到rollback segment中,可进行回滚。truncate执行是立即生效的,不记录行删除信息,而是直接重构表,所以不能回滚;
5.delete执行后,会产生数据碎片,只删除数据,不会改变表空间大小。truncate执行后,数据库表会恢复至初始状态。
五.union与union all的区别
1、union: 对两个结果集进行并集操作, 不包括重复行,相当于distinct, 同时进行默认规则的排序;会对获取的结果进行排序操作
2、union all: 对两个结果集进行并集操作, 包括重复行, 即所有的结果全部显示, 不管是不是重复;不会对获取的结果进行排序操作
union all只是合并查询结果,并不会进行去重和排序操作,在没有去重的前提下,使用union all的执行效率要比union高
六.left join,right join inner join区别
-
LEFT JOIN 左连接,以左侧表为主,右侧表与其相匹配,匹配不上的记录 ,以null 做替补;
-
RIGHT JOIN右连接,以右侧表为主,左侧表与其相匹配,匹配不上得记录,以null做替补;
-
INNER JOIN内连接,取交集。
七.MySQL执行流程
- 客户端发起 SQL 查询,首先通过连接器,它会检查用户的身份,包括校验账户密码,权限,然后会查询缓存,如果缓存命中直接返回,如果没有命中再执行后续操作,但是MySQL8.0 之后已经删除了缓存功能;
- 接下来到达分析器,主要检查语法词法,比如 SQL 有没有写错,总共有多少关键字;要查询哪些东西;
- 然后到达优化器,他会以自己的方式优化我们的 SQL;
- 最后到达执行器,调用存储引擎执行 SQL 并返回结果。
八.MySQL语句执行顺序
from->on->join->where->group by->having->select->distinct->order by->limit
九.说说数据库设计三范式
- 第一范式:任何一张表都应该有自己的主键,并且每一个字段的原子性都是不可再分的。
- 列唯一,每一个字段具有原子性不可再分;
- 每一张表都有主键。
- 第二范式:在第一范式的基础上,要求所有的非主键字段完全依赖主键,不能产生部分依赖。
- 行唯一
- 第三范式:在第二范式的基础上,所有非主键只能依赖于主键,不能产生传递依赖。
- 存在外键,比如学生表中可以有班级表的主键进行关联。
十.CHAR 和 VARCHAR 的区别
char是一种固定长度的类型,无论储存的数据有多少都会固定长度,如果插入的长度小于定义长度,则可以用空格进行填充。而varchar是一种可变长度的类型,当插入的长度小于定义长度时,插入多长就存多长。
- char最大长度是255字符,varchar最大长度是65535个字节。
- char是定长的,不足的部分用隐藏空格填充,varchar是不定长的。
- char会浪费空间,varchar会更加节省空间。
- char查找效率会很高,varchar查找效率会更低。
- 尾部空格:char插入时可省略,varchar插入时不会省略,查找时省略。
十一.DDL,DML优化手段有哪些,批量插入
-
DDL:在导入数据时,可以通过禁用索引来提高导入数据性能 。这个操作主要针对有数据的表,追加数据。
-
DML:变多次事务提交为一次事务提交。批量插入
insert into test values(1,2),(1,3),(1,4);
十二.MySQL存储引擎
-
InnoDB存储引擎
InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。
- 支持事务,行锁,表锁,不支持全文索引,数据库宕机后可以恢复数据。
-
MyISAM存储引擎
MyISAM拥有较高的插入、查询速度,但不支持事物。
- 不支持外键,数据崩溃后无法恢复,只支持表锁。
-
MEMORY存储引擎
不支持事务
表级锁定
读写相互阻塞,写入不能读,读时不能写
只缓存索引
不支持外键约束
不支持聚簇索引
读取数据较快,占用资源少
不支持MVCC 高并发 (多版本并发控制机制)
崩溃恢复性较差
mysql 5.5.5 前的默认数据引擎(show engines; 查看)
- 不支持外键
功 能 MYISAM Memory InnoDB Archive 存储限制 256TB RAM 64TB None 支持事物 No No Yes No 支持全文索引 Yes No No No 支持数索引 Yes Yes Yes No 支持哈希索引 No Yes No No 支持数据缓存 No N/A Yes No 支持外键 No No Yes No
十三.MySQL行锁与表锁
-
行锁:MySQL中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁和排他锁。InnoDB存储引擎默认采用行锁。InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。
特点:行锁开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
-
表锁:MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。
特点:表锁开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发最低。
十四.MySQL索引有哪些类型
- 普通索引:允许重复的值
- 唯一索引:不允许有重复的值
- 主键索引:数据库自动为我们的主键创建索引,如果我们没有指定主键,它会根据没有 null 的唯一索引创建主键索引,否则会默认根据一个隐藏的 rowId 作为主键索引
- 全文索引,用来对文本域进行索引,比如 text,varchar,只针对 MyISAM 有效
十五.索引方式有哪些
B+树和 hash,Myisam 和 innodb 都不支持 hash。
十六.索引失效的情况有哪些
- like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。
- or语句前后没有同时使用索引。
- 当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效
- 组合索引,不是使用第一列索引,索引失效。
- 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
- 数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描。
- 在索引列上使用 IS NULL 或 IS NOT NULL操作。
- 索引是不索引空值的,所以这样的操作不能使用索引
- 在索引字段上使用not,<>,!=。
- 不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 优化方法: key<>0 改为 key>0 or key<0。
- 对索引字段进行计算操作、字段上使用函数。
- 当全表扫描速度比索引速度快时,mysql会使用全表扫描,此时索引失效。
- 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
十七.MySQL索引的数据结构,B+树的特点
- 数据结构:B+树,HASH。
- 特点
- 非叶子节点仅具有索引作用,也就是说,非叶子节点只能存储Key,不能存储value
- 树的所有叶节点构成一个有序链表,可以按照key排序的次序依次遍历全部数据。
十八.MySQL主从复制原理
- 主要依靠 binlog 来实现的,它记录的是所有的 DDL,DML,TCL 操作
- 当主库的数据发生改变时,会将改变记录保存到 binloga2 中
- 主库新开一个线程将 binlog 内容发送到从库
- 从库会发起一个 I/O 线程请求主库的 binlog,并保存到中继日志中
- 从库新开一个 SQL 线程,读取中继日志并解析成具体操作,从而将主库更新的内容写到了从库中
十九.集群模式有哪些,分别有什么优缺点?
- 主从复制:一主一从,一主多从,主负责读写,从只能读,一对一或一对多关系。
- 哨兵模式:基于主从模式,哨兵实际上是一个单独进程,用来监听主服务是否宕机,如果宕机则将从转为主,并且通知其他的服务器修改配置文件,让它们切换主机。哨兵模式也可配置多哨兵,多哨兵之间互相监控。
- 集群模式:集群是将应用复制成多个相同应用,分散在不同服务器,每个服务器都独立运行相同的代码,可以分散服务器压力解决高并发问题,同时也能预防单点节点故障,就是一台服务器故障并不影响其他服务器正常运行,但没有解决单体应用代码臃肿,业务复杂,维护性差等问题。
常见的MySQL面试题有哪些?
本文主要介绍我在公司招聘的时候,主要问应聘者的一些问题,希望对换工作的同行及在使用过程中有些疑问的同行有所帮助
1. MySQL海量数据优化
优化问题主要从SQL优化、事务级别调整、MySql配置参数调整做起
1.1. SQL优化
- 避免使用OR
- 不要使用like %xx %在左边时索引失效
- 使用复合索引时没有遵循最左匹配原则
- 不要让数据类型出现隐式转化
- 不要在索引字段上使用not,<>,!=,一样会导致索引失效
- 分解关联查询
- 小表驱动大表 即小的数据集驱动大的数据集
1.2. 事务级别调整
首先了解下事务的隔离级别,数据库共定义了四种隔离级别:
- Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)
- Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)
- Read committed:可避免脏读情况发生(读已提交)。
- Read uncommitted:最低级别,以上情况均无法保证。(读未提交)
可以通过 set transaction isolation level 设置事务隔离级别来提高性能
1.3. MySql配置参数
#基础配置
datadir=/data/datafile
socket=/var/lib/mysql/mysql.sock
log-error=/data/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
character_set_server=utf8#允许任意IP访问
bind-address = 0.0.0.0#是否支持符号链接,即数据库或表可以存储在my.cnf中指定datadir之外的分区或目录,为0不开启#symbolic-links=0#支持大小写
lower_case_table_names=1#二进制配置
server-id = 1
log-bin = /data/log/mysql-bin.log
log-bin-index =/data/log/binlog.index
log_bin_trust_function_creators=1
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION#InnoDB存储数据字典、内部数据结构的缓冲池,16MB已经足够大了。
innodb_additional_mem_pool_size = 16M#InnoDB用于缓存数据、索引、锁、插入缓冲、数据字典等#如果是专用的DB服务器,且以InnoDB引擎为主的场景,通常可设置物理内存的60%#如果是非专用DB服务器,可以先尝试设置成内存的1/4
innodb_buffer_pool_size = 4G#InnoDB的log buffer,通常设置为 64MB 就足够了
innodb_log_buffer_size = 64M#InnoDB redo log大小,通常设置256MB 就足够了
innodb_log_file_size = 256M#InnoDB redo log文件组,通常设置为 2 就足够了
innodb_log_files_in_group = 2
innodb_file_per_table = 1#InnoDB共享表空间初始化大小,默认是 10MB,改成 1GB,并且自动扩展
innodb_data_file_path = ibdata1:1G:autoextend#设置临时表空间最大4G
innodb_temp_data_file_path=ibtmp1:500M:autoextend:max:4096M#启用InnoDB的status file,便于管理员查看以及监控
innodb_status_file = 1#当设置为0,该模式速度最快,但不太安全,mysqld进程的崩溃会导致上一秒钟所有事务数据的丢失。#当设置为1,该模式是最安全的,但也是最慢的一种方式。在mysqld 服务崩溃或者服务器主机crash的情况下,binary log 只有可能丢失最多一个语句或者一个事务。#当设置为2,该模式速度较快,也比0安全,只有在操作系统崩溃或者系统断电的情况下,上一秒钟所有事务数据才可能丢失。
innodb_flush_log_at_trx_commit = 1
max_connections=600
max_connect_errors=1000
max_user_connections=400#设置临时表最大值,这是每次连接都会分配,不宜设置过大 max_heap_table_size 和 tmp_table_size 要设置一样大
max_heap_table_size = 100M
tmp_table_size = 100M#每个连接都会分配的一些排序、连接等缓冲,一般设置为 2MB 就足够了
sort_buffer_size = 2M
join_buffer_size = 2M
read_buffer_size = 2M
read_rnd_buffer_size = 2M#建议关闭query cache,有些时候对性能反而是一种损害
query_cache_size = 0
key_buffer_size = 8M
long_query_time = 120
slow_query_log=1 #开启mysql慢sql的日志
log_output=table,File #日志输出会写表,也会写日志文件,为了便于程序去统计,所以最好写表
slow_query_log_file=/data/log/slow.log
innodb_buffer_pool_dump_at_shutdown=1
innodb_buffer_pool_load_at_startup=1#打印deadlock日志
innodb_print_all_deadlocks=1
2. MySql数据表分区如何设计
数据表分区主要是解决监控数据过大造成的单表数据量过大,在存储及查询的过程中对性能造成影响,通过数据表分区,减小数据文件的大小,提高磁盘读写性能。
分区设计:
- 时间阀值需求,指标明细保留90天,趋势数据保留3年
- 监控的指标数据需要能查询90天内的明细,所以原始明细数据保留90天,指标多及监控间隔时间短,必然产生大量的数据
- 每天一个分区存储原始数据
- 统计趋势数据,及删除超过90天的明细数据
数据表分区规划示意图
3. 如何启用Mysql查询缓存
数据库优化中,除了Sql本身之外,数据库本身的优化也是很重要的一个环节,缓存就是其中一项。
查看查询缓存情况:
mysql> show variables like %query_cache%;
(query_cache_type 为 ON 表示已经开启)
+------------------------------+----------+| Variable_name | Value |
+------------------------------+----------+
| have_query_cache | YES || query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 || query_cache_size | 20971520 |
| query_cache_type | ON || query_cache_wlock_invalidate | OFF |
+------------------------------+----------+
如果不是ON,修改/etc/my.cnf配置文件以开启查询缓存:
[mysqld]中添加:
query_cache_size = 20M
query_cache_type = ON
重启mysql服务使配置查询缓存配置生效:
> service mysql restart
4. MySQL配置文件字符集可以通过指令改吗?
可以的,MySql8.x支持动态修改配置参数
1、可以的,通过 set global 命令直接修改,不用重启mysql
2、要是8.x 可以用 set persist 新特性
示例:
mysql> set persist max_connections=default;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from performance_schema.persisted_variables;
+-----------------+----------------+
| VARIABLE_NAME | VARIABLE_VALUE |
+-----------------+----------------+
| max_connections | 151 |
+-----------------+----------------+
1 row in set (0.00 sec)
mysql> show variables like %max_connections%;
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| max_connections | 151 |
| mysqlx_max_connections | 100 |
+------------------------+-------+
2 rows in set (0.01 sec)
主要分享低代码、微服务、容器化、SAAS、系统架构方面的的内容,希望大家点赞,评论,关注。
以上是关于常见数据库优化面试题的主要内容,如果未能解决你的问题,请参考以下文章