【数据库】

目录

数据库面试题

表结构数据

datetime 和 timestamp的区别

存储范围不同:
datetime 是 1000-01-01 00:00:01.000000 到 9999-12-31 23:59:59.999999
timestamp 是 1970-01-01 00:00:01.000000 到 2038
时区相关:
datetime 存储与时区无关,而timestamp,mysql会将时间从当前服务器的时区转化成UTC进行存储,查询时从UTC转换为当前时区进行返回。
存储大小:
datetime 占用空间更大

主键

主键是数据库确保数据行在整张表唯一性的保障,推荐使用自增ID,不要使用 UUID。
因为在 InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降.

MySQL 中的 varchar 和 char 有什么区别?

char 是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容。该字段都占用 10 个字符,而 varchar 是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度 +1,最后一个字符存储字符串长度;
在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用 char,否则应该尽量使用 varchar。例如存储用户 MD5 加密后的密码,则应该使用 char。

varchar(10) 和 int(10) 代表什么含义?

varchar的10代表了申请的空间长度,也是可以存储的数据的最大长度,而int的10只是代表了展示的长度,不足10位以0填充.(也就是说,int(5) 和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示.)

MySQL的binlog有有几种录入格式?分别有什么区别?

有三种格式:statement、row和mixed.
statement模式下,记录单元为语句.即每一个sql造成的影响会记录.由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制.
row级别下,记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大.
mixed. 一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row.

超大分页怎么处理?

超大的分页一般从两个方向上来解决.:
数据库层面,使用覆盖索引,先把主键查出来,在根据主键查询数据。(类似于select * from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit 10,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.)
从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

说一说三个范式?

第一范式: 每个列都不可以再拆分。
第二范式: 非主键列完全依赖于主键,而不能是依赖于主键的一部分。(联合主键)
第三范式: 非主键列只依赖于主键,不依赖于其他非主键。
在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的原因。比如性能,事实上我们经常会为了性能而妥协数据库的设计。

left join、right join以及inner join的区别?

left join:左关联,主表在左边,右边为从表。如果左侧的主表中没有关联字段,会用null 填满
right join:右关联 主表在右边和letf join相反
inner join: 内关联只会显示主表和从表相关联的字段,不会出现null

常见的约束有哪几种?

主键约束:primary key;
外键约束:foreign key;
唯一约束:unique;
检查约束:check;
空值约束:not null;
默认值约束:default;

什么是sql注入?

SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。

简述数据库的读写分离?

第一台数据库服务器,是对外提供增删改业务的生产服务器;第二台数据库服务器,主要进行读的操作。

count(1)、count(*)与count(列名)的执行区别

执行效果上 :
count():包括了所有的列,相当于行数,在统计结果的时候, 不会忽略列值为NULL
count(1):包括了忽略所有列,用1代表代码行,在统计结果的时候, 不会忽略列值为NULL
count(列名):只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数, 即某个字段值为NULL时,不统计。
执行效率上:
列名为主键,count(列名)会比count(1)快
列名不为主键,count(1)会比count(列名)快
如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(

如果有主键,则 select count(主键)的执行效率是最优的
如果表只有一个字段,则 select count(*)最优。

sql中null与空值的区别

1.占用空间区别:空值(’’)的长度是0,是不占用空间的;而的NULL长度是NULL,是占用空间的
2.插入/查询方式区别:NULL值查询使用is null/is not null查询,而空值(’’)可以使用=或者!=、<、>等算术运算符。
3.COUNT 和 IFNULL函数:使用 COUNT(字段) 统计会过滤掉 NULL 值,但是不会过滤掉空值。
4.索引字段说明:在有NULL值的字段上使用常用的索引,如普通索引、复合索引、全文索引等不会使索引失效。在官网查看在空间索引的情况下,说明了 索引列必须为NOT NULL。

索引

索引的类型

普通索引、唯一索引、主键索引、组合索引
普通索引:基本的索引类型,没有唯一性限制,允许为null
唯一索引:数据不允许重复,允许为null
主键索引:数据不允许重复,不允许为null,一个表只能有一个主键
组合索引:多列值组成一个索引,用于组合搜索

如何避免索引失效

遵循最佳左前缀原则
查询条件从最左前列开始并且不跳过索引中的列。
不在索引列上做任何操作(计算、函数、(自动or手动)类型转换)
不要在作为范围条件的索引列的右边列使用索引
如果在 where 查询条件中使用到了所有的复合索引的列,其中中间列是范围匹配,则会导致该列的右边的所有列都不会生效。
如:select * from role where user_id=1 and dept_id>1 and role_name=‘老师’;
不要使用 != 或者 <> ,会导致全表扫描( 5.7 版本以后的只会降低效率,不会导致索引失效)
不使用 like以通配符开头(如:‘%abc…’)
如何解决 like 以通配符开头导致索引失效?
使用覆盖索引(查询的列是复合索引的部分列或者全部列,主键索引可添加到查询列中)

索引的数据结构

索引的数据结构和具体的存储引擎有关,在MySql中使用较多的索引有Hash索引、B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引是B+树索引。

为什么使用索引

通过创建唯一索引,可以保证数据库表中没一行数据的唯一性;
可以大大加快数据的检索速度,这也是创建索引最主要的原因;
帮助服务器避免排序和临时表;
将随机IO变成顺序IO;
可以加速表和表之间的连接。
索引的缺点
时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
空间方面:索引需要占物理空间。

Innodb为什么要用自增id作为主键

如果表使用自增主键,那么每次插入新的数据,数据就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页。如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值相当于随机,因此每次新数据都要被插到现有索引页得中间某个位置,这样 频繁的移动、分页操作就造成了大量的碎片,得到的索引结构也不够紧凑,后续就不得不通过optimize来优化表。

什么是聚簇索引

聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行数据。
在InnoDB中,只有主键索引是聚簇索引,如果没有主键,就挑选一个唯一索引。如果也没有,Mysql就自动为InnoDB表生成一个隐含字段来建立聚簇索引(这个字段长度为6个字节,长整形)
当查询使用聚簇索引时,在对应的叶子节点可以获取到整行数据,因此不用再次进行回表操作。

聚簇索引和非聚簇索引的区别

聚簇索引的叶子节点存放的是主键值和数据行,(支持覆盖索引)
非聚簇索引的叶子节点存放的是主键值或数据行的地址(InnoDB辅助索引的data域存储相应记录主键的值,MyISAM辅助索引的data域保存数据记录的地址)

什么是覆盖索引

如果一个索引包含所有需要查询的字段的值,就称为覆盖索引。
在InnoDB存储引 擎中,如果不是主键索引,叶子节点存储的是主键值。最终还是要“回表”,也就是要通过主键再查找一次,这样就 会比较慢。覆盖索引就是把要查询出的列和索引是对应的,不做回表操作!

非聚簇索引一定会回表查询吗?

不一定,如果查询语句要查询的字段是索引字段,就不必再进行回表查询。
举个简单的例子,假设我们在用户表的年龄上建立了索引,那么当进行select age from employee where age < 20的查询时,在索引的叶子节点上,已经包含了age信息,不会再次进行回表查询。

MyISAM和InnoDB实现B+树索引方式的区别是什么?

InnoDB 主键索引使用的是聚簇索引,MyISAM 不管是主键索引,还是其他索引使用的都是非聚簇索引。
在根据主键索引搜索时,直接找到key所在的节点即可取出数据;根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。 因此,在设计表的时候,不建议使用过长的字段为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。
MyISAM,B+Tree叶节点的data域存放的是数据记录的地址,在索引检索的时候,首先按照B+Tree搜索算法搜索索引,如果指定的key存在,则取出其data域的值,然后以data域的值为地址读取相应的数据记录,这被称为“非聚簇索引”;
InnoDB,其数据文件本身就是索引文件,相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的节点data域保存了完整的数据记录,这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引,这被称为“聚簇索引”或者聚集索引,而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。

索引的底层实现

Hash索引
基于哈希表实现,只有精确匹配索引所有列的查询才有效,对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),并且Hash索引将所有的哈希码存储在索引中,同时在索引表中保存指向每个数据行的指针。
B-Tree索引(MySQL使用B+Tree)
B-Tree能加快数据的访问速度,因为存储引擎不再需要进行全表扫描来获取数据,数据分布在各个节点之中。
B+Tree索引
是B-Tree的改进版本,同时也是数据库索引所采用的存储结构。数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都指向相邻的叶子节点的地址。相比B-Tree来说,进行范围查找时只需要查找两个节点,进行遍历即可。而B-Tree需要获取所有节点,相比之下B+Tree效率更高。

Hash 索引和 B+ 树索引有什么区别或者说优劣呢?

首先要知道 Hash 索引和 B+ 树索引的底层实现原理:
hash 索引底层就是 hash 表,进行查找时,调用一次 hash 函数就可以获取到相应的键值,之后进行回表查询获得实际数据。B+ 树底层实现是多路平衡查找树。对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据。
那么可以看出他们有以下的不同:
hash 索引进行等值查询更快(一般情况下),但是却无法进行范围查询。
因为在 hash 索引中经过 hash 函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询。而 B+ 树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围。
hash 索引不支持使用索引进行排序,原理同上。
hash 索引不支持模糊查询以及多列索引的最左前缀匹配。原理也是因为 hash 函数的不可预测。
hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询
hash 索引虽然在等值查询上较快,但是不稳定。性能不可预测,当某个键值存在大量重复的时候,发生 hash 碰撞,此时效率可能极差。而 B+ 树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低。
因此,在大多数情况下,直接选择 B+ 树索引可以获得稳定且较好的查询速度。而不需要使用 hash 索引。

创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

MySQL 提供了 explain 命令来查看语句的执行结构分析,MySQL 在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的分析,其中包含了许多信息。可以通过其中和索引有关的信息来分析是否用到了索引。
“执行计划”中需要知道的几个“关键字”
id :编号
select_type :查询类型
table :表
type :类型
possible_keys :预测用到的索引
key :实际使用的索引
key_len :实际使用索引的长度
ref :表之间的引用
rows :通过索引查询到的数据量
Extra :额外的信息

为什么Mysql用B+树做索引而不用B-树或红黑树、二叉树

主要原因:B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,而B树只能中序遍历所有节点,效率太低。

索引在什么情况下遵循最左前缀的规则?

在建立了联合索引的前提条件下,数据库会一直从左向右的顺序依次查找,直到遇到了范围查询(>,<,between,like等)

事务

事务的特性 ACID

A(Atomicity):原子性,就是要么全部成功,要么全部失败。不可能只执行一部分操作。
C(Consistency):一致性,事务执行前后,数据从一个状态到另一个状态必须是一致的(A向B转账,不能出现A扣了钱,B却没收到)。
I(Isolation):隔离性,多个事务之间相互隔离,不能互相干扰。
D(Durability):持久性,一旦事务提交,那么就永远是这样子了,哪怕系统崩溃也不会影响到这个事务的结果。

MySQL中为什么要有事务回滚机制?

在 MySQL 中,恢复机制是通过回滚日志(undo log)实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后在对数据库中的对应行进行写入。当事务已经被提交之后,就无法再次回滚了。
回滚日志作用:
能够在发生错误或者用户执行 ROLLBACK 时提供回滚相关的信息
在整个系统发生崩溃、数据库进程直接被杀死后,当用户再次启动数据库进程时,还能够立刻通过查询回滚日志将之前未完成的事务进行回滚。(这也就需要回滚日志必须先于数据持久化到磁盘上,是我们需要先写日志后写数据库的主要原因。)

数据库并发事务会带来哪些问题?

数据库并发事务会带来 脏读、幻读、丢弃更改、不可重复读 这四个常见问题,其中:
脏读:A 事务读取到了 B 事务未提交的内容,但是之后B事务未满足一致性等特性而做了回滚操作,那么读取事务得到的结果就是脏数据了。
幻读:A 事务读取了一个范围的内容,而同时 B 事务在此期间插入(删除)了一条数据。造成"幻觉"。
丢弃修改:两个写事务T1 T2同时对A=0进行递增操作,结果T2覆盖T1,导致最终结果是1 而不是2,事务被覆盖
不可重复读:当设置T2事务只能读取 T1 事务已经提交的部分,T2 读取一个数据,然后T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。
(不可重复读的重点是修改,幻读的重点在于新增或者删除。)
MySQL 的事务隔离级别
MySQL 的四种隔离级别如下:
未提交读(READ UNCOMMITTED):事务中发生了修改,即使没有提交,其他事务也是可见的,(比如对于一个数A原来50修改为100,但是我还没有提交修改,另一个事务看到这个修改,而这个时候原事务发生了回滚,这时候A还是50,但是另一个事务看到的A是100.可能会导致脏读、幻读或不可重复读)
已提交读(READ COMMITTED):对于一个事务从开始直到提交之前,所做的任何修改是其他事务不可见的,(举例就是对于一个数A原来是50,然后提交修改成100,这个时候另一个事务在A提交修改之前,读取的A是50,刚读取完,A就被修改成100,这个时候另一个事务再进行读取发现A就突然变成100了;可以阻止脏读,但是幻读或不可重复读仍有可能发生)
可重复读(REPEATABLE READ):就是对一个记录读取多次的记录是相同的,比如对于一个数A读取的话一直是A,前后两次读取的A是一致的;可以阻止脏读和不可重复读,但幻读仍有可能发生
可串行化(SERIALIZABLE):在并发情况下,和串行化的读取的结果是一致的,没有什么不同,比如不会发生脏读和幻读;该级别可以防止脏读、不可重复读以及幻读
请添加图片描述

Innodb使用的是哪种隔离级别呢?

MySQL InnoDB默认支持的隔离级别是 可重复读(REPEATABLE-READ)
原因: 与 SQL 标准不同的地方在于InnoDB 存储引擎在 REPEATABLE-READ(可重读)事务隔离级别下 使用的是 Next-Key Lock 锁算法 ,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以 说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读) 已经可以完全保证事务的隔离性要 求,即达到了 SQL标准的SERIALIZABLE(可串行化)隔离级别。
InnoDB 存储引擎在分布式事务 的情况下一般会用到SERIALIZABLE(可串行化)隔离级别。

锁相关

Mysql的锁的作用

当数据库有并发事务的时候,可能会导致数据不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。

mysql有哪几种锁

按照 锁的粒度 划分可以分成:行锁、表锁、页锁
按照 使用的方式 划分可以分为:共享锁、排它锁
按照 思想 的划分:乐观锁、悲观锁
行级锁:行级锁是mysql中锁定粒度最小的一种锁。表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突,但加锁的开销是最大的。行级锁分为共享锁和排他锁(开销大,加锁慢,会出现死锁。发生锁冲突的概率最低,并发度也最高)
表级锁:表级锁是mysql中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分mysql引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)
特点: 开销小,加锁快,不会出现死锁。发生锁冲突的概率最高,并发度也最低。
页级锁:页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折衷的页级锁,一次锁定相邻的一组记录。(开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般)

共享锁:共享锁又称读锁,是读取操作创建的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。
用法:SELECT … LOCK IN SHARE MODE;
在查询语句后面增加lock in share mode,MySQL 就会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据。
排他锁:排他锁又称写锁、独占锁,如果事务T对数据A加上排他锁后,则其他事务不能再对A加任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
用法:SELECT … FOR UPDATE;
在查询语句后面增加for update,MySQL 就会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。

数据库悲观锁和乐观锁的原理和应用场景分别有什么?

悲观锁,先获取锁,再进行业务操作,一般就是利用类似 SELECT … FOR UPDATE 这样的语句,对数据加锁,避免其他事务意外修改数据。当数据库执行SELECT … FOR UPDATE时会获取被select中的数据行的行锁,select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
乐观锁,先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过。Java 并发包中的 AtomicFieldUpdater 类似,也是利用 CAS 机制,并不会对数据加锁,而是通过对比数据的时间戳或者版本号,来实现乐观锁需要的版本判断。
乐观锁(Optimistic Lock):就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量.(像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。乐观锁不能解决脏读的问题。)
悲观锁(Pessimistic Lock):就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。(假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。)

InnoDB 存储引擎有几种锁算法?

Record Lock — 单个行记录上的锁;
Gap Lock — 间隙锁,锁定一个范围,不包括记录本身;
Next-Key Lock — 锁定一个范围,包括记录本身

mysql死锁的案例

批量入库,存在则更新,不存在则插入
当对存在的行进行锁的时候(主键),mysql就只有行锁。
当对未存在的行进行锁的时候(即使条件为主键),mysql是会锁住一段范围(间隙锁)
锁住的范围为:(无穷小或小于表中锁住id的最大值,无穷大或大于表中锁住id的最小值)
如:(22无值)如果表中目前有已有的id为(11 , 12),那么就锁住(12,无穷大);
如果表中目前已有的id为(11 , 30),那么就锁住(11,30)。(间隙锁是允许共存的)

如何处理死锁?

设置超时时间,一直等待直到超时;(通过配置文件my.ini 字段innod_block_wait_timeout来)
发起死锁检测,发现死锁之后,主动回滚死锁中的事务,不需要其他事务继续
(设置innodbdeadlockdetect设置为on可以主动检测死锁,在innodb中这个值默认就是on开启的状态)

如何避免死锁?

为了在单个innodb表上执行多个并发写入操作时避免死锁,可以在事务开始时,通过为预期要修改行,使用select …for update语句来获取必要的锁,即使这些行的更改语句是在之后才执行的
在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应先申请共享锁,更新时在申请排他锁。因为这时候当用户在申请排他锁时,其他事务可能又已经获得了相同记录的共享锁
如果事务需要修改或锁定多个表,则应在每个事务中以相同的顺序使用加锁语句。在应用中,如果不同的程序会并发获取多个表,应尽量约定以相同的顺序来访问表,这样可以大大降低产生死锁的机会

Innodb默认是如何对待死锁的?

innodb默认是使用设置死锁时间来让死锁超时的策略,默认innodblockwait_timeout设置的时长是50s

什么是全局锁?它的应用场景有哪些?

全局锁就是对整个数据库实例加锁,它的典型使用场景就是做全库逻辑备份,这个命令可以使用整个库处于只读状态,使用该命令之后,数据更新语句,数据定义语句,更新类事务的提交语句等操作都会被阻塞。

使用全局锁会导致的问题?

如果在主库备份,在备份期间不能更新,业务停止,所以更新业务会处于等待状态
如果在从库备份,在备份期间不能执行主库同步的binlog,导致主从延迟

优化锁方面你有什么建议?

尽量使用较低的隔离级别。
精心设计索引, 并尽量使用索引访问数据, 使加锁更精确, 从而减少锁冲突的机会。
选择合理的事务大小,小事务发生锁冲突的几率也更小。
给记录集显示加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁。
不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会。
尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响。
不要申请超过实际需要的锁级别。
除非必须,查询时不要显示加锁。 MySQL 的 MVCC 可以实现事务中的查询不用加锁,优化事务性能;MVCC 只在 COMMITTED READ(读提交)和 REPEATABLE READ(可重复读)两种隔离级别下工作。
对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。

复杂问题

MySQL数据库cpu飙升的话,要怎么处理呢?

排查过程:
使用top 命令观察,确定是mysql导致还是其他原因。
如果是mysqld导致的,show processlist,查看session情况,确定是不是有消耗资源的sql在运行。
找出消耗高的 sql,看看执行计划是否准确, 索引是否缺失,数据量是否太大。
处理:
kill 掉这些线程(同时观察 cpu 使用率是否下降),
进行相应的调整(比如说加索引、改 sql、改内存参数)
重新跑这些 SQL。

MYSQL的主从延迟,你怎么解决?

主从复制分了五个步骤进行:
步骤一:主库的更新事件(update、insert、delete)被写到binlog
步骤二:从库发起连接,连接到主库。
步骤三:此时主库创建一个binlog dump thread,把binlog的内容发送到从库。
步骤四:从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log
步骤五:还会创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db
主从同步延迟的原因:
一个服务器开放N个链接给客户端来连接的,这样有会有大并发的更新操作, 但是从服务器的里面读取binlog的线程仅有一个,当某个SQL在从服务器上执行的时间稍长 或者由于某个SQL要进行锁表就会导致,主服务器的SQL大量积压,未被同步到从服务器里。这就导致了主从不一致, 也就是主从延迟。
主从同步延迟的解决办法:
主服务器要负责更新操作,对安全性的要求比从服务器要高,所以有些设置参数可以修改,比如sync_binlog=1,innodb_flush_log_at_trx_commit = 1 之类的设置等。
选择更好的硬件设备作为slave。
把一台从服务器当度作为备份使用, 而不提供查询, 那边他的负载下来了, 执行relay log 里面的SQL效率自然就高了。
增加从服务器,这个目的还是分散读的压力,从而降低服务器负载。

如果让你做分库与分表的设计,简单说说你会怎么做?

分库分表方案:
水平分库:以字段为依据,按照一定策略(hash、range等),将一个库中的数据拆分到多个库中。
水平分表:以字段为依据,按照一定策略(hash、range等),将一个表中的数据拆分到多个表中。
垂直分库:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。
垂直分表:以字段为依据,按照字段的活跃性,将表中字段拆到不同的表(主表和扩展表)中。

常用的分库分表中间件:

sharding-jdbc
Mycat

分库分表可能遇到的问题:

事务问题:需要用分布式事务
跨节点Join的问题:解决这一问题可以分两次查询实现
跨节点的count,order by,group by以及聚合函数问题:分别在各个节点上得到结果后在应用程序端进行合并。
数据迁移,容量规划,扩容等问题
ID问题:数据库被切分后,不能再依赖数据库自身的主键生成机制,最简单可以考虑UUID
跨分片的排序分页问题

日常工作中你是怎么优化SQL的?

(1.1)表结构优化
尽量使用数字型字段
若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
尽可能的使用 varchar 代替 char
变长字段存储空间小,可以节省存储空间。
当索引列大量重复数据时,可以把索引删除掉
比如有一列是性别,几乎只有男、女、未知,这样的索引是无效的。
(1.2)查询优化
应尽量避免在 where 子句中使用!=或<>操作符
应尽量避免在 where 子句中使用 or 来连接条件
任何查询也不要出现select *
避免在 where 子句中对字段进行 null 值判断
(1.3)索引优化
对作为查询条件和 order by的字段建立索引
避免建立过多的索引,多使用组合索引
(1.4)慢查询优化
分析语句,是否加载了不必要的字段/数据
分析 SQL 执行句话,是否命中索引等
如果 SQL 很复杂,优化 SQL 结构
如果表数据量太大,考虑分表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值