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