赞
踩
select distinct <列名>
from <表名>
where <查询条件表达式>
group by <分组的列名>
having <分组后的查询条件表达式>
order by <排序的列名>
asc\desc <升序\降序>
limit <查询的记录条数>
select student.student_id,student.student_name,student.student_sex,SUM(score.student_score)
from student
left join score
on student.student_id=score.student_id
group BY student.student_id
ORDER BY SUM(score.student_score)
desc
limit 2
每门课程大于80分——》最低分不小于80分
select student.student_id,student.student_name,student.student_sex,MIN(score.student_score)
from student
left join score
on student.student_id=score.student_id
group BY student.student_id
HAVING MIN(score.student_score)>50
ORDER BY MIN(score.student_score)
desc
order by:
group by:
1、where是条件查询语句,一般用于select * from 表名 where;
having用户分组查询,有having必定使用group by。
2、where查询条件中不可以使用聚合函数;
而having查询条件中可以使用聚合函数。
3、where用于分组前进行过滤;
having用于分组后进行过滤。
4、WHERE 根据数据表中的字段直接进行过滤;
而 HAVING 是根据前面已经查询出的字段进行过滤。
5、WHERE 查询条件中不可以使用字段别名;
而 HAVING 查询条件中可以使用字段别名。
1.数据存储方式:非关系型数据库的存储方式是KEY-VALUE的形式、文档等形式(redis),而关系型数据库只支持单一的存储方式(mysql)。
2.查询效率:关系型数据库存储于磁盘,非关系型数据库存储于缓存,效率比关系型数据库更高。
3.事务:关系型数据库支持事务处理,可进行事务回滚。
4.成本:非关系型数据库基本是开源的,不需要像oracle花费大量的成本购买
1、使用适合的索引:
2、避免全表扫描:
3、优化查询语句:
4、避免使用SELECT *
5、使用合适的数据类型
6、分页查询优化
7、定期维护数据库
8、in中值太多
如果使用了in,即使后面的条件加了索引,还是要注意in后面的元素不要过多哈。in元素一般建议不要超过500个,如果超过了,建议分组,每次500一组进行哈。
如果我们对in的条件不做任何限制的话,该查询语句一次性可能会查询出非常多的数据,很容易导致接口超时。尤其有时候,我们是用的子查询。如下这种子查询:
9、将常用的查询放入到缓冲
https://blog.csdn.net/qq_36227301/article/details/89418949
统计日志
slow log:慢查询日志,超出预设的long_query_time阈值的sql记录;默认没有开启慢查询日志。
慢查询:全名是慢查询日志,它可以记录执行速度较慢的sql,从而可以通过它分析执行速度较慢的sql,为后续优化提供参考建议。
mysql是默认关闭查询日志的,所以需要先开启慢查询日志后,并进行相关配置后,才能查看慢查询日志。
因为开启查询日志消耗性能。在测试环境开启慢查询日志,生产环境只在定位问题的适合才开启
查看日志开关是否打开:show variables like “%query%”;
打开日志开关:set global slow_query_log=‘ON’;
设置阈值:set long_query_time=0.01;
执行sql语句
查看日志内容
修改日志存放格式:set global log_output=“table”;
查看表中内容:select * from mysql.slow_log;
连接器:连接管理,权限验证
查询缓存:命中直接返回结果
分析器:语法分析(分析关键字)
优化器:生成执行计划,选择索引
执行器:操作引擎,返回结果
索引是一种数据结构,可以帮助我们快速的进行数据的查找。
索引包含一个表中列的值,并且这些值存储在一个数据结构中。
将索引可以类比为书的目录。
可以大大加快数据的检索速度
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
将随机IO变为顺序IO;通过索引对数据进行排序,降低数据排序的成本,降低了CPU的消耗。
可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
需要花时间研究建立优秀的索引,或者优化
时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
空间方面:索引需要占物理空间。
普通索引
唯一索引(主键索引、唯一索引)
联合索引
全文索引
空间索引
主键自动建立唯一索引
频繁作为查询条件的字段应该创建索引
查询中与其他表关联的字段,外键关系建立索引
查询中排序的字段
索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。
索引的原理很简单,就是把无序的数据变成有序的查询
把创建了索引的列的内容进行排序
模拟优化器执行sql查询语句
分析查询语句或是表结构的性能瓶颈
explain + sql语句
表的读取顺序
数据读取操作的操作类型
哪些索引可以使用
哪些索引被实际使用
表之间的引用
每张表有多少行被优化器查询
概念:事务指一个操作序列,该操作序列中的多个操作要么都做要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位。
1)原子性
原子是自然界最小的颗粒,具有不可再分的特性。事务中的所有操作可以看做一个原子,事务是应用中不可再分的最小的逻辑执行体。使用事务对数据进行修改的操作序列,要么全部执行,要么全不执行。通常,某个事务中的操作都具有共同的目标,并且是相互依赖的。如果数据库系统只执行这些操作中的一部分,则可能会破坏事务的总体目标,而原子性消除了系统只处理部分操作的可能性。
2) 一致性
一致性是指事务执行的结果必须使数据库从一个一致性状态,变到另一个一致性状态。当数据库中只包含事务成功提交的结果时,数据库处于一致性状态。一致性是通过原子性来保证的。例如:在转账时,只有保证转出和转入的金额一致才能构成事务。也就是说事务发生前和发生后,数据的总额依然匹配。
3) 隔离性
隔离性是指各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务,都是隔离的。也就是说:并发执行的事务之间既不能看到对方的中间状态,也不能相互影响。
例如:在转账时,只有当A账户中的转出和B账户中转入操作都执行成功后才能看到A账户中的金额减少以及B账户中的金额增多。并且其他的事务对于转账操作的事务是不能产生任何影响的。
4)持久性
持久性指事务一旦提交,对数据所做的任何改变,都要记录到永久存储器中,通常是保存进物理数据库,即使数据库出现故障,提交的数据也应该能够恢复。但如果是由于外部原因导致的数据库故障,如硬盘被损坏,那么之前提交的数据则有可能会丢失。
当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复读的重点是修改,幻读的重点在于新增或者删除。
解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
例1(同样的条件, 你读取过的数据, 再次读取出来发现值不一样了 ):事务1中的A先生读取自己的工资为 1000的操作还没完成,事务2中的B先生就修改了A的工资为2000,导致A再读自己的工资时工资变为 2000;这就是不可重复读。
例2(同样的条件, 第1次和第2次读出来的记录数不一样 ):假某工资单表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,共查到4条记录,这时事务2 又插入了一条工资大于3000的记录,事务1再次读取时查到的记录就变为了5条,这样就导致了幻读
使用索引进行查询的时候必须遵循的是最左匹配原则。所谓最左匹配原则,就是查询的条件属性必须从索引的最左边开始,中间不能有间隙。
对于那些数据量大,并且需要频繁的读写,一定需要做缓存的
需要去数据库中频繁的读和写,为了项目提高运行效率,可以把用户的权限在每次登录的时候都缓存到redis中。
权限列表(特点:哪些数据量大,并且需要频繁的读写,一定需要做缓存的)
检查缓存是否被命中:在某些缓存系统中,可以通过查看缓存命中率来确定请求是否命中了缓存。如果命中率非常高,那么很可能当前的请求是走的缓存。
检查缓存的过期时间:一般来说,缓存会设置一个过期时间,当缓存过期了,再次访问时会从数据库中获取最新数据并更新缓存。如果当前数据的时间在缓存的过期时间内,那么该数据可能是从缓存中取出的。
打印日志:开发协助,在请求经过缓存层时,可以在日志中添加一条记录,标记该请求经过了缓存。这样在问题排查时,可以通过查看日志来确认。
什么是索引:
索引是一种数据结构,可以帮助我们快速的进行数据的查找。
索引的优点
可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
索引的缺点
时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
空间方面:索引需要占物理空间。
主键
指一个列或者是多个列的组合,它的值能唯一地标识表中的每一行。
主键是一种特殊的索引,并且是唯一性索引的一种,定义为:PRIMARY_KEY
主键有那些特点
1、一个表中只能有一个主键;
2、主键可以是一个字段,也可以是多个字段组成主键;
3、设置为主键的字段不能重复;
4、设置为主键的字段不能为空;
主键的优势
1、提高数据的检索速度;
2、保证数据的唯一性;
3、保证实体的完整性;
外键
表的外键是另一表的主键, 外键可以有重复的, 可以是空值;
用来和其他表建立联系用的
一个表可以有多个外键
当程序中可能出现并发的情况时,就需要保证在并发情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和他单独操作时的结果是一样的。这就叫做并发控制。并发控制的目的是确保一个用户的工作不会对其他的用户工作产生不合理的影响。
没有做好控制,就可能导致脏读、幻读、不可重复读
实现并发控制的主要手段分为乐观并发控制和悲观并发控制。
无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。乐观锁比较适用于读多写少的情况(多读场景),悲观锁比较适用于写多读少的情况(多写场景)。
当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对数据进行加锁以防止并发。这种借助数据库锁机制,【Pessimistic Concurrency Control,缩写“PCC”,又名“悲观锁”】。
悲观锁,具有强烈的独占性和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。
悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)
之所以叫做悲观锁,是因为这是一种对数据的修改持有悲观态度的并发控制方式。总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起。悲观锁的实现:
悲观锁主要分为共享锁和排他锁:
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。
乐观锁采取了更加宽松的加锁机制。也是为了避免数据库幻读、业务处理时间过长等原因引起数据处理错误的一种机制,但乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性。乐观锁的实现:
只要我们在 SQL 前加上 explain,就可以分析出,当前环境下 MySQL 的“查询方式”以及“索引选择”。
id:每个select语句操作的唯一标识
select_type:查询的类型,我们可以根据该字段判断查询的性质,包括查询是简单/复杂查询类型
table:查询的表名的别名
type:关联的类型
possible_keys:查询可能会使用哪些索引,这列是基于查询访问的列来判断的
key:mysql最终决定使用那个索引
key_len:mysql在索引里使用的字节数
ref:查找所用的的列/常量
rows:mysql估算的预计扫描行数
all:全表扫描
index:按照索引进行全表扫描,如果查询不是覆盖索引的,可能会产生大量的随机IO
system:表里就一条数据
fulltext:关联使用了全文索引
1、sql没有加索引
where
的条件列,建立索引,尽量避免全表扫描。2、sql索引没生效
索引不生效的场景
隐式的类型转换,索引失效
查询条件包含or,可能导致索引失效
like通配符可能导致索引失效
查询条件不满足联合索引的最左匹配原则
在索引列上使用了mysql的内置函数
对索引进行列运算(加减乘除)
索引列上使用(!=)
索引字段上使用is null、is not null
3、单表数据量太大
4、join或者子查询太多
数据库有个规范约定就是:尽量不要有超过3个以上的表连接。
join过多的问题:一方面,过多的表连接,会大大增加SQL复杂度。另一方面,如果join的数据量比较大时,mysql会采用在硬盘上创建临时表的方式进行多张表的关联匹配,这种显然效率就极低,本来磁盘的 IO 就不快,还要关联。
一般情况下,如果业务需要的话,关联2~3个表是可以接受的,但是关联的字段需要加索引哈。如果需要关联更多的表,建议从代码层面进行拆分,在业务层先查询一张表的数据,然后以关联字段作为条件查询关联表形成map,然后在业务层进行数据的拼装。
5、in元素过多
如果使用了in,即使后面的条件加了索引,还是要注意in后面的元素不要过多哈。in元素一般建议不要超过500个,如果超过了,建议分组,每次500一组进行哈。
如果我们对in的条件不做任何限制的话,该查询语句一次性可能会查询出非常多的数据,很容易导致接口超时。尤其有时候,我们是用的子查询。如下这种子查询:
6、拿不到锁
有时候,我们查询一条很简单的SQL,但是却等待很长的时间,不见结果返回。一般这种时候就是表被锁住了,或者要查询的某一行或者几行被锁住了。我们只能慢慢等待锁被释放。
这时候,我们可以用show processlist命令,看看当前语句处于什么状态
7、delete+in子查询没有索引
8、系统或网络资源不够
9、limit深分页问题
select * from 表名 where create_time> ‘2024-02-14’ limit 100000,10;
原因
limit深分页,导致SQL变慢原因有两个:
limit语句会先扫描offset+n行,然后再丢弃掉前offset行,返回后n行数据。也就是说limit 100000,10,就会扫描100010行,而limit 0,10,只扫描10行。
limit 100000,10 扫描更多的行数,也意味着回表更多的次数原文链接:
10、数据库参数配置问题:
11、缓存问题
12、数据库设计问题
主从模式指的是将主数据库部署在多个服务器上,当主节点写入数据的时候会同步到从节点。
实现高可用,当一个节点发生故障后切换到另一个节点
可以实现读写分离,避免一个数据库压力太大,性能低。
可以实现数据备份,每一个数据库是一个数据备份。
Mysql的主从复制的大致流程是这样的:
Drop直接删掉表;
Truncate删除表中数据,再插入时自增长id又从1开始 ;
Delete删除表中数据,可以加where字句
1、最大长度:
char最大长度是255个字符,varchar最大长度是65535个字符。
2、char是定长的,不足的部分会用隐藏空格填充,varchar是不定长的。
当向char中插入数据时,如果该数据小于定义的长度,那么就会用空格填充不足的部分;
当向varchar中插入数据时,如果数据小于定义的长度,那么按数据的实际长度存储,即插入多长就存多长;当要存储的数据的实际长度大于定义的长度时,会对该数据进行自动截取。
3、空间使用:
char会浪费空间,varchar会更加节省空间。
4、查找效率:
char查找效率会很高,varchar查找效率会更低。
因为char的长度固定,故char的存取速度还是要比varchar快得多,存储与查找会更加方便;但是char也为此付出了空间的代价,因为其长度固定,所以会占据多余的空间,可谓是以空间换取时间效率。varchar则刚好相反,是以时间换空间,存储与查找相比于char效率更低一些。
5、尾部空格:
char插入时可省略,varchar插入时不会省略,但查找时省略。
left join:左关联,主表在左边,右边为从表。如果左侧的主表中没有关联字段,会用null 填满
right join:右关联 主表在右边和letf join相反
inner join: 内关联只会显示主表和从表相关联的字段,不会出现null
排查过程:
使用top 命令观察,确定是mysqld导致还是其他原因。
在服务器上执行mysql -u root -p之后,输入show full processlist; 可以看到正在执行的语句。
找出消耗高的 sql,看看执行计划是否准确, 索引是否缺失,数据量是否太大。
处理:
kill 掉这些线程(同时观察 cpu 使用率是否下降),
进行相应的调整(比如说加索引、改 sql(首先是缩减查询范围)、改内存参数)
重新跑这些 SQL。
count() :统计所有的行数,包括为null的行(COUNT()不单会进行全表扫描,也会对表的每个字段进行扫描。
count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL。
count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空。
1.占用空间区别:空值(’’)的长度是0,是不占用空间的;而的NULL长度是NULL,是占用空间的
2.插入/查询方式区别:NULL值查询使用is null/is not null查询,而空值(’’)可以使用=或者!=、<、>等算术运算符。
3.COUNT 和 IFNULL函数:使用 COUNT(字段) 统计会过滤掉 NULL 值,但是不会过滤掉空值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。