数据库基础
求平局值用什么,分组用什么
统计平局值:avg
分组:group by
两个结果集求并集用什么
union 并集 , union all(允许重复)
完整查询SQL中的关键字的定义顺序
SELECT 列名 FROM 表1 JOIN 表2 ON 条件 WHERE 条件 GROUP BY 列名 HAVING 条件 ORDER BY 列名 LIMIT
完整的多表JOIN查询,SQL中关键字的执行顺序
FROM --> ON --> JOIN --> WHERE --> GROUP BY --> HAVING --> ORDER BY --> LIMIT
索引部分
什么是索引
索引是用来高效获取数据的存储结构如同字典的目录一样,数据库的索引通常使用b+tree来实现,索引树的节点和数据地址相关联,查询的时候在索引树种进行高效搜索,然后根据数据地址获取数据。索引提高了搜索的效率同时增加了索引维护的成本,滥用索引也会降低insert,update,delete的性能。
Mysql索引有哪些类型
普通索引:允许重复的值
唯一索引:不允许有重复的值
主键索引:数据库自动为我们的主键创建索引,如果我们没有指定主键,它会根据没有null的唯一索引创建主键索引,否则会默认根据一个隐藏的rowId作为主键索引
全文索引,用来对文本域进行索引,比如text,varchar,只针对MyISAM有效
索引方式有哪些
B+树和hash,Myisam和innodb都不支持hash
Mysql的索引结构原理
采用了B+树的数据结构,采用B+树的原因,B+树是多叉树,适合存储大量数据,B+树的数据存储在叶子节点,内部节点只存键值,因此B+树每次查询都要走到叶子节点, 查询性能更稳定,同时它的非叶子节点只存储key,因此每个节点能存储更多的key,树的高度变的更低,查询性能更快,而且它的叶子节点能够形成一个链表,支持范围查询,排序 。
InnoDB的索引结构和MyIsam的索引结构有什么区别
他们都是用的B+树,不同的是
- innodb的叶子节点存放的是数据,myisam的叶子节点存放的是数据的地址
- innodb中辅助索引的叶子节点存放的是主键索引的键值,myisam中辅助索引的叶子节点存放的也是数据的地址
- innodb的索引和数据都存放到一个文件中,myisam的索引和数据分别存放到不同的文件中
哪些列不适合创建索引
不经常查询的列不适合创建索引
不出现在where中的字段不适合创建索引
离散度太低的字段不适合创建索引,比如性别
更新非常频繁的字段不适合创建索引,因为会导致索引频繁更细,性能差。
哪些因素会造成索引失效
模糊查询时,通配符放到左边的时候,会导致索引失效 比如 like ‘’%keyword%’’
列是字符串类型,查询条件没有用引号,会导致索引失效
使用了or,in,not in,not exist, !=等,会导致索引失效
查询null值,会导致索引失效
还有mySQL认为全表扫描会比索引查找快,就不会使用索引,比如表里只有一条记录
什么是辅助索引&什么是覆盖索引
除了主键索引之外的其他索引都叫辅助索引,也叫二级检索。辅助索引的叶子节点存储的是主键索引的键值,因此辅助索引扫描完之后还会扫描主键索引,这也叫回表
但是如果查询的列恰好包含在辅助索引的键值中,就不会再回表了,这也叫覆盖索引
InnoDB辅助索引的叶子节点也存数据吗
InnoDB辅助索引的叶子节点存放的是,主键索引的键值
因此辅助索引扫描完还会扫描主键索引,也叫回表
但是如果查询的列恰好包含在辅助索引的键值中,就不会再回表了,这也叫覆盖索引
组合索引的匹配原则
组合索引向左匹配,我们应该优先选择组合索引,因为对覆盖索引命中率更高,查询性能更高,但是应该考虑列的顺序,因为组合索引会向左匹配
Like一定会让索引失效吗
不一定,比如:like “值%” 一样可以使用索引,向左匹配,而 like "%值"或 "_值"就不能命中索引。
索引创建的原则有哪些
查询较频繁的列应该考虑创建索引
不经常查询的列不适合创建索引
不出现在where中的字段不适合创建索引
离散度太低的字段不适合创建索引,比如性别
更新非常频繁的字段不适合创建索引
数据库优化
哪些因素可能会造成数据库性能问题
不合理的商业需求,比如实时更新总注册人数,总交易额等等,应该考虑不要实时
对于热点数据的查询并发太高,应该考虑用缓存
数据库结构设计不合理,比如几十个字段集中在一张表,应该考虑分表
SQL语句有问题,比如太多JOIN,很多不需要的字段也要全部查询出来,应该考虑优化SQL
硬件和网络方面的影响
Mysql的执行流程是怎么样的
客户端发起SQL查询,首先通过连接器,它会检查用户的身份,包括校验账户密码,权限
然后会查询缓存,如果缓存命中直接返回,如果没有命中再执行后续操作,但是MySQL8.0之后已经删除了缓存功能
接下来到达分析器,主要检查语法词法,比如SQL有没有写错,总共有多少关键字,要查询哪些东西
然后到达优化器,他会以自己的方式优化我们的SQL
最后到达执行器,调用存储引擎执行SQL并返回结果
优化SQL你从哪些方面着手
不需要的字段就不要查询出来
小结果集驱动大结果集,将能过率更多数据的条件写到前面
in和not in尽量不要用,会导致索引失效
避免在where中使用or链接条件,这会导致索引失效
给经常要查询的字段建立索引
考虑如果不需要事务,并且主要查询的化,可以考虑使用MyISAM存储引擎
如果表数据量实在太庞大了,考虑分表
如何去定位慢SQL
通过druid连接池的内置监控来定位慢SQL
通过MySQL的慢查询日志查看慢SQL
通过show processlist,查看当前数据库SQL执行情况来定位慢SQL
页面上发起的一个查询很慢,你怎么去优化
首先看一下硬件和网络层面,有没有什么异常
然后分析代码有没有什么问题,算法有没有什么缺陷,比如多层嵌套循环
最后我们再定位到慢SQL,比如
- 通过druid连接池的内置监控来定位慢SQL
- 通过MySQL的慢查询日志查看慢SQL
- 通过show processlist,查看当前数据库SQL执行情况来定位慢SQL
定位到慢SQL再考虑优化该SQL,比如说
- 不需要的字段就不要查询出来
- 小结果集驱动大结果集,将能过率更多数据的条件写到前面
- in和not in尽量不要用,会导致索引失效
- 避免在where中使用or链接条件,这会导致索引失效
- 考虑如果不需要事务,并且主要查询的化,可以考虑使用MyISAM存储引擎
如果优化SQL后还是很慢,可以考虑给查询字段建索引来提升效率
如果建立索引了还是慢,看一下是不是数据量太庞大了,应该考虑分表了
你如何看SQL有没有命中索引
在SQL语句前加上explain,结果中的key就是实际用到的索引
mysql存储引擎有哪些,有什么区别,如何选择
主要有innodb,memory,myisam
innodb支持事务,速度相对较慢,支持外键,不支持全文索引
myisam 速度相对较快,支持全文索引,不支持外键,不支持事务,
memory不支持事务,基于内存读写,速度快,支持全文索引
如果对事务要求不高,而且是查询为主,考虑用myisam
如果对事务要求高,保存的都是重要的数据,建议使用innodb,它也是默认的存储引擎
如果数据频繁变化的,不需要持久化,可以使用memory
下面SQL如何优化
一个sql : select sum(amount) from recharge ,来查询总充值,recharge 表数据量达到了上千万,怎么优化
可以考虑建个汇总表来统计总充值,总订单数,总人数等等等
或者采用日报表,月报表,年报表,使用定时任务进行结算的方式来统计
或者看数据能不能使用ES搜索引擎来优化,如果非得要在这个上千万的表中来查询,那就采用分表
事务相关
什么是事务
一组对数据库的操作,把这一组看成一个再给你,要么全部成功,要么全部失败。
举个栗子,比如A向B转账,A账户的钱少了,B账户的钱就应该对应增加,这就转账成功了,如果A账户的钱少了,由于网络波动等因素转账失败了,B账户的钱没有增加,那么A账户就应该恢复成原先的状态
事务的四大特性
原子性:指的是一个事务应该是一个最小的无法分割的单元,不允许部分成功部分失败,只能同时成功,或者同时失败
持久性:一旦提交事务,那么数据就应该持久化,保证数据不会丢失
隔离性:两个事务修改同一个数据,必须按顺序执行,并且前一个事务如果未完成,那么中间状态对另一个事务不可见
一致性:要求任何写到数据库的数据都必须满足预先定义的规则,它基于其他三个特性实现的
InnoDB如何保证原子性和持久性的
通过undo log 保证事务的原子性,redo log保证事务的持久性
undo log是回滚日志,记录的是回滚需要的信息,redo log记录的是新数据的备份
当事务开始时,会先保存一个undo log,再执行修改,并保存一个redo log,最后再提交事务。如果系统崩溃数据保存失败了,可以根据redo log中的内容,从新恢复到最新状态,如果事务需要回滚,就根据undo log 回滚到之前的状态
事务并发问题有哪些
脏读:事务A读到了事务B修改还未提交的数据
幻读,也叫虚读:事务A两次读取相同条件的数据,两次查询到的数据条数不一致,是由于事务B再这两次查询中插入或删除了数据造成的
不可重复读:事务A两次读取相同条件的数据,结果读取出不同的结果,是由于事务B再这两次查询中修改了数据造成的
第一类丢失更新:也叫回滚丢失,事务A和事务B更新同一条数据,事务B先完成了修改,此时事务A异常终止,回滚后造成事务B的更新也丢失了
第二类丢失更新:也叫覆盖丢失,事务A和事务B更新同一条数据,事务B先完成了修改,事务A再次修改并提交,把事务B提交的数据给覆盖了
事务隔离级别有哪些,分别能解决什么问题
读未提交:事务读不阻塞其他事务的读和写,事务写阻塞其他事务的写但不阻塞读,能解决第一类丢失更新的问题,
读已提交:事务读不会阻塞其他事务读和写,事务写会阻塞其他事务的读和写,能解决第一类丢失更新,脏读的问题
可重复读:事务读会阻塞其他事务的写但不阻塞读,事务写会阻塞其他事务读和写,能解决第一类丢失更新,脏读,不可重复读,第二类丢失更新问题
串行化:使用表级锁,让事务一个一个的按顺序执行,能解决以上所有并发安全问题
MySql的InnoDB是如何保证原子性的
利用了undo log实现的
undo log记录了这些回滚需要的信息,当事务执行失败或调用了rollback,导致事务需要回滚,就可以利用undo log中的信息将数据回滚到修改之前的样子
MySql的InnoDB是如何保证持久性的
利用了redo log实现的
redo log记录的是新数据的备份,在事务提交前,需要将Redo Log持久化,当系统崩溃时,可以根据redo Log的内容,将所有数据恢复到最新的状态
说一下事务的执行流程(Undolog+Redolog)
假设有A=1,B=2,两个数据,现在有个事务把A修改为3,B修改为4,那么事务的执行流程:
当事务开始时,会首先记录A=1到undo log,记录A=3到redo log,和记录B=2到undo log,记录B=4到redo log,然后再将redo log写入磁盘,最终事务提交
解释一下事务并发丢失更新问题,·如何解决
第一类丢失更新:也叫回滚丢失,事务A和事务B更新同一条数据,事务B先完成了修改,此时事务A异常终止,回滚后造成事务B的更新也丢失了
第二类丢失更新:也叫覆盖丢失,事务A和事务B更新同一条数据,事务B先完成了修改,事务A再次修改并提交,把事务B提交的数据给覆盖了
SQL标准中的四种隔离级别,读未提交,读已提交,可重复读,串行化,都能解决第一类数据更新丢失问题
对于第二类丢失更新问题,可以使用悲观锁也就是串行化来解决,也可以使用乐观锁的方式,比如加一个版本号管理来解决
InnoDB事务隔离的实现原理是什么
隔离的实现主要利用了读写锁和MVCC机制
读写锁,要求在每次读操作时需要获取一个共享锁,写操作时需要获取一个写锁。共享锁之间不会产生互斥,共享锁和写锁,写锁与写锁之间会产生互斥。当产生锁竞争时,需要等一个操作的锁释放,另一个操作才能获得锁
MVCC,多版本并发控制,它是在读取数据时通过一种类似快照的方式将数据保存下来,不同的事务看到的快照版本是不一样的,即使其他事务修改了数据,但是对本事务仍然是不可见的,它只会看到第一次查询到的数据
可重复读是只在事务开始的时候生成一个当前事务全局性的快照,而读提交则是每次执行语句的时候都重新生成一次快照
数据库集群
Mysql主从解决什么问题,不能解决什么问题?
MySQL主从同步,主负责写,从负责读,使用一主多从,能减轻读的压力
但是这不能解决写的压力和主库的单点故障,如果主库的写并发高,可以做成多个主库
MySql主从复制原理?
主要依靠binlog来实现的,它记录的是所有的DDL,DML,TCL操作
当主库的数据发生改变时,会将改变记录保存到binlog中
从库新开一个线程将binlog内容发送到从库
从库会发起一个I/O线程请求主库的binlog,并保存到中继日志中
从库新开一个SQL线程,读取中继日志并解析成具体操作,从而将主库更新的内容写到了从库中
MySql主从配置步骤?
安装mySQL主从客户端,并配置my.ini
主库需要配置授权从库使用的账号和权限,启动后可以通过show 主库名 status查看状态,我们需要记录File和Position的值,File是对应的binlog文件名,position是当前同步数据的最新行
从库需要配置主库链接信息,包括账号密码和binlog文件名和最新行,然后启动。通过show 从库名 status 检查同步状态,Slave_IO_Running 和 Slave_SQL_Running 的值都为YES,说明大功告成了
什么是垂直分表,垂直分库,水平分表,水平分库
垂直分表,可以理解为按列分表,如果一个表的字段太多了,可以按照使用频率分成不同的表,优化查询性能。比如商品表可以分为商品类型表,商品详情表,商品促销表等等
垂直分库,为了减轻单个数据库压力,我们可以按照业务类型,拆分成多个数据库,比如分布式架构,不同的模块可以有不同的数据库
水平分表,可以理解为按行分表,如果一个表的数据有千万行,查询性能太低,可以拆分成10张小表,每张表保存一百万行数据
水平分库,我们做了水平分表后,表数量太多了也会影响数据库查询效率,我们可以将这些表分到多个数据库中
分库分表后会出现哪些问题?怎么解决
会产生分布式事务,以前本地事务就能结局的问题现在要用上Seata分布式事务
垂直分库后跨库查询会导致一个查询结果来源于两个库,可能要用到多线程调用多个库查询
水平分库后一个分页查询的某一页可能来自两个库,可以将两个库的数据合并之后再执行SQL
水平分表后不同的表出现主键重复,可以通过雪花算法来解决
两个库都用到同一个表,那这个公共表的维护可能要用到MySQL主从同步
你们公司使用的是什么技术来水平分表?还可以有什么技术?有什么区别?
使用的是sharding-jdbc来实现的,它是由java开发的关系型数据库中间件,读写分离,分库分表操作简单
TDDL,淘宝业务框架,复杂而且分库分表的部分还没有开源
Mycat,要安装额外的环境,不稳定用起来复杂
MySQL官方提供的中间件,不支持大数据量的分不分表,性能较差
你们使用什么规则来分库分表的?还有哪些规则?
垂直分库,按照业务进行垂直分库,比如课程表和用户表放到不同数据库
垂直分表,把多字段表拆分少量字段表,比如将课程表分为课程类型表,课程详情表,课程促销表等
水平分表,把海量数据表拆分为多个小表
把商品业务进行水平分库,可以对水平分库后每一个数据库服务器进行集群
你从哪些方面去优化你的数据库?
如果是并发高,可以考虑缓存,如果是数据量大可以考虑分库分表,具体如下:
首先应该考虑垂直分库,不同的业务使用不同的数据库
然后进行垂直分表,按照使用频率把字段多的表拆分成若干个表
对经常查询的列建立索引,提高查询效率
设计冗余字段,减少join表的次数
SQL优化,比如尽量使用索引查询
对热点数据应该考虑做缓存,比如首页展示汇总数据
从海量数据中查询数据应该考虑用全文检索
如果查询并发高,可以对mySQL做集群
如果数据量实在太大了,可以考虑水平分表,
水平分表后,表数量还是太多了,可以考虑水平分库
Mysql的集群有哪些模式?
一主一从;一主多从;双主;环形多主;级联同步
单机优化到极致了,可以怎么优化?
可以考虑做集群,比如一主多从模式,然后对应用做读写分离
多机优化有哪些方式?
分表,分库,主从同步
解释一下分库分表的含义?
垂直分表,可以理解为按列分表,如果一个表的字段太多了,可以按照使用频率分成不同的表,优化查询性能。比如商品表可以分为商品类型表,商品详情表,商品促销表等等
垂直分库,为了减轻单个数据库压力,我们可以按照业务类型,拆分成多个数据库,比如分布式架构,不同的模块可以有不同的数据库
水平分表,可以理解为按行分表,如果一个表的数据有千万行,查询性能太低,可以拆分成10张小表,每张表保存一百万行数据
水平分库,我们做了水平分表后,表数量太多了也会影响数据库查询效率,我们可以将这些表分到多个数据库中
水平分表有哪些分表规则?
按照区间范围分表,比如把用户按照年龄分为新生代表,青年代表,老年代表
按照时间分表,比如按照年来分表,比如登录日志,分成今年的表,去年的表。。
hash分表,通过将某一列的值比如id,通过一定的hash算法来算出对应那张表
雪花算法,通过雪花算法生成id,根据id来算出对应那张表
能简单说一下你怎么使用shardingjdbc做读写分离的嘛
首先导入相关的依赖
然后在配置文件中配置datasource,包括主从数据库的名字,主从数据库的连接信息,配置负载均衡
项目中就可以正常使用datasource了,自动做读写分离
能简单说一下你怎么使用shardingjdbc做读分库分表的嘛
首先,要改造数据库,比如水平分表,水平分库
在配置文件中,需要做如下配置
- datasource名字,多个数据源就配多个datasource
- 分库策略,比如按照哪一列分库,分库规则
- 分表策略,比如哪些库下面的哪些表,按照那一列分表,分表规则
- 配置公共的表
然后项目中就可以正常使用了