一. Mysql 优化从如下三个方面着手:
一、表的设计
1、使用InnoDB存储引擎(事采用行锁,适合高并发操作);
2、使用默认utf8 / mb4字符集(减少转码风险);
优先选用数字类型;能 用char 不用varchar, 字段设置为not null;
3、禁止使用外键(外键会导致表之间耦合高,影响增删改操作的性能);
4、禁止使用触发器、视图、存储过程和event
5、表和字段使用中文注释--便于后人理解;
二 架构方向:
- 对数据库性能影响较大的特性少用;
- 数据库擅长索引和存储,尽量少的占用数据库(应将计算集中在服务层,禁止存大文件或者照片,在数据库里存储URI);
3、必须把字段定义为NOT NULL(null值需要额外的存储空间);
4、减少非必要的大量的大字段(大字段会影响数据库的查询性能);
三 索引:
1、单表索引控制在5个以内
2、单索引不超过5个字段--超过5个以及起不到有效过滤数据的效果
3、建立组合索引,必须把区分度高的字段放在前边--更加有效的过滤数据
4、数据区分度不大的字段不易使用索引--例如:性别只有男,女,订单状态,每次过滤数据很少
==================================================================================
▌1.表结构和索引的优化
如左面的模块,应该掌握如下6个原则:
第1个原则:要在设计表结构时,考虑数据库的水平与垂直扩展能力,提前规划好未来1年的数据量、读写量的增长,规划好分库分表方案。比如设计用户信息表,预计1年后用户数据10亿条,写QPS约5000,读QPS30000,可以设计按UID纬度进行散列,分为4个库每个库32张表,单表数据量控制在KW级别;
第2个原则:要为字段选择合适的数据类型,在保留扩展能力的前提下,优先选用较小的数据结构。例如保存年龄的字段,要使用TINYINT而不要使用INT;
第3个原则:可以将字段多的表分解成多个表,必要时增加中间表进行关联。假如一张表有4、50个字段显然不是一个好的设计;
第4个原则:是设计关系数据库时需要满足第三范式,但为了满足第三范式,我们可能会拆分出多张表。而在进行查询时需要对多张表进行关联查询,有时为了提高查询效率,会降低范式的要求,在表中保存一定的冗余信息,也叫做反范式。但要注意反范式一定要适度;
第5个原则:要善于用索引,比如为经常作为查询条件的字段创建索引、创建联合索引时要根据最左原则考虑索引的复用能力,不要重复创建索引;要为保证数据不能重复的字段创建唯一索引等等。不过要注意索引对插入、更新等写操作是有代价的,不要滥用索引。比如像性别这样唯一很差的字段就不适合建立索引;
第6个原则:列字段尽量设置为Not Null,MySQL难以对使用Null的列进行查询优化,允许Null会使索引、索引统计和值更加复杂。允许Null值的列需要更多的存储空间,还需要MySQL内部进行特殊处理。
▌2.SQL语句进行优化的原则
如右面的模块,共分5个原则:
第1个原则:要找的最需要优化的SQL语句。要么是使用最频繁的语句,要么是优化后提高最明显的语句,可以通过查询MySQL的慢查询日志来发现需要进行优化的SQL语句;
第2个原则:要学会利用MySQL提供的分析工具。例如使用Explain来分析语句的执行计划,看看是否使用了索引,使用了哪个索引,扫描了多少记录,是否使用文件排序等等。或者利用Profile命令来分析某个语句执行过程中各个分步的耗时;
第3个原则:要注意使用查询语句是要避免使用Select *,而是应该指定具体需要获取的字段。原因一是可以避免查询出不需要使用的字段,二是可以避免查询列字段的元信息;
第4个原则:是尽量使用Prepared Statements,一个是性能更好,另一个是可以防止SQL注入;
第5个原则:是尽量使用索引扫描来进行排序,也就是尽量在有索引的字段上进行排序操作。
以上为数据库操作须掌握的内容,可以进行差缺补漏,希望对研发人员有一定的帮助。
===========================================================================================
mysql优化我一般遵从五个原则:
减少数据访问: 设置合理的字段类型,启用压缩,通过索引访问等减少磁盘IO
返回更少的数据: 只返回需要的字段和数据分页处理 减少磁盘io及网络io
减少交互次数: 批量DML操作,函数存储等减少数据连接次数
减少服务器CPU开销: 尽量减少数据库排序操作,和全表查询 减少cpu 内存占用利用更多资源: 使用表分区,可以增加并行操作,更大限度利用cpu资源
sql语句常见的优化比如
sql优化第一最基本的为了最快的速度查询到数据,减少消耗,尽量避免全表查询,首先考虑在where和order by字段上建立索引
where子句条件 后不要使用!=和》《操作符,否则数据库会放弃索引使用全表查询
.用like模糊查询时不建议在查询字段开头或首尾两端使用百分号,这也会导致字段放弃索引,全表查询,可以考虑百分号在查询字段后面或者使用全文索引
在sql中直接使用计算表达式和函数,也会导致索引失败,可以在等号右边计算
不要写select * from 需要什么字段返回什么字段减少消耗
在sql语句中嵌套SQL查询 ,不要使用iN 或者 not in 可以使用 exists替代
对于复杂的查询,可以使用中间临时表 暂存数据
查询数据量大的表 会造成查询缓慢。主要的原因是扫描行数过多。这个时候可以通过程序,分段分页进行查询,循环遍历,将结果合并处理进行展示。
要查询100000到100050的数据
SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY ID ASC) AS rowid,* FROM infoTab)t WHERE t.rowid > 100000 AND t.rowid <= 100050
3 对数据量较大的表,使用分区分表存储
4 一定要定期维护数据表和优化索引,删除空余数据
5 尽量使用数字型字段
尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会 逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
SQL优化的原因:
性能低 执行时间长 等待时间长;
sql语句欠佳(链接查询)索引失效,服务器参数设置不合理(比如缓冲区 线程数)
1 什么时候【要】创建索引
(1)表经常进行 SELECT 操作
(2)表很大(记录超多),记录内容分布范围很广
(3)列名经常在 WHERE 子句或连接条件中出现
2 什么时候【不要】创建索引
(1)表经常进行 INSERT/UPDATE/DELETE 操作
(2)表很小(记录超少)
(3)列名不经常作为连接条件或出现在 WHERE 子句中
3 索引优缺点:
a: 索引加快数据库的检索速度,提高系统的性能
b: 索引会降低增删改的效率;
c索引不是所有情况均适用,(少量数据 ,频繁改动的数据,很少使用的字段);
d: 索引本身很大 要存放在内存/硬盘中,需要占物理和数据空间;
SQL优化的具体操作:
- 在表中建立索引,优先考虑where、group by使用到的字段。
【1】查询语句中不要使用select * from ...,换成select 字段a ,字段b where ... ;因为*会增加数据路的工作量;
【2】尽量减少子查询,使用关联查询(left join, right join, inner join)代替;因为子查询效率非常低,尤其数据量多的时候;
【3】对于连续的数值,能用 between 就不要用 in ;尽量避免使用in 和not in,使用exists,not exists或者关联查询语句代替;
因为IN或者NOT IN 有时候会导致数据库引擎放弃索引进行全表扫描;
【4】
a: 应尽量避免在 where 子句中使用 or 来连接条件会造成全表扫描
尽量用union或者union all代替(在确认没有重复数据或者不用剔除重复数据时,union all会更好);因为or会上导致索引失效;
b: 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描;
c: 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描;
【7】建表的时候优先使用数字类型(type,status…),数字类型查询速度快,字符串检索起来慢。(因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了);
【13】使用复合索引要遵循最佳左前缀原则
a. 不要夸列或者无序使用,尽量使用全索引匹配;
b 对于复合索引,如果左侧索引失效,右侧索引全部失效;
c 不要在索引上进行任何操作(如 计算,函数,类型转换),否则索引失效。
d 复合索引不能使用( !=, <, >, is null ,is not null) ,否则自身以及右侧所有全部失效。
最佳左前缀法则(带头索引不能死,中间索引不能断):在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致;
【14】对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差;
【15】一个表的索引数最好不要超过5个.(因为索引会提高查询的效率 但是会降低增删改的效率,因为 insert 或 update 时有可能会重建索引);
【16】尽可能的使用 varchar代替 char(变长字段存储空间小,且查询起来效率更高);
【17】使用like关键字模糊查询时,% 放在前面会导致索引失效(like ‘文%’这样索引才会生效);
【18】对查询进行优化,应尽量避免全表扫描,首先应考虑在where以及order by涉及的列上建立索引。
6、尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。
8、当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描。如下:
SELECT * FROM t WHERE 1=1
优化方式:用代码拼装sql时进行判断,没where加where,有where加and。
10.程序要尽量避免大事务操作,提高系统并发能力。
8、如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则索引将会失效。
9、不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描。
11、尽量使用覆盖索引(只访问索引的查询(索引和查询列一致)),减少select*。——按需取数据用多少取多少。
===================================================================================
- 1. 字段属性选择上:
尽量设置为NOT NULL (数据库查询的时候 不用比较NULL值) ;
文本字段 如 省份 姓名, 可以定位为ENUM类型(数值型数据被处理的速度比文本类型快);
字段的长度越小越好,如果可以的话 可以用MEDIUMINT 代替BIGINT;
能用数字类型字段 尽量不使用字符类型,因为引擎在处理查询和连接时 会比较字符串中的没一个字符,而对于数字型而言只需要比较一次就够了,所以,字符类型会降低查询和连接的性能 增加存储开销;
2. 尽量使用连结(JOIN)来代替子查询(Sub-Queries);
3. 用explain查询sql语句 对查询进行优化,
要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。4. 使用索引【单一索引, 组合索引, 唯一索引;】
没有索引 查询会进行全表扫描 速度比较慢,加了索引走索引 速度比较快;
优先给where、 JOIN, order by 后面的字段创建索引;避免给数据库中某个含有大量重复值的字段建立索引,尽量不要在有索引的字段上使用函数操作 会导致索引失效;
索引可以提高查询的效率 但是会降低增删改的效率,索引也不是越多越好 其固然提高了响应查询的效率,但同时降低了insert update 的效率, 因为insert update可能会重新创建索引, 所以怎样创建索引需要慎重考虑,且一张表中最多不超过6个索引。
一般情况下,不鼓励使用like,比如 使用 like"%MySQL%" 会导致索引失效, 非使用的话 like 尽量 以' 常量'开头,不要以'%'开头, 否则索引失效,可以替换成 like"MySQL%" ;
ps
只要列中包含有NULL值都将不会被包含在索引中, 复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL;
- 复合索引:(最佳左前缀)
a. 不要夸列或者无序使用,尽量使用全索引匹配;
b 对于复合索引,如果左侧索引失效,右侧索引全部失效;
c 不要在索引上进行任何操作(如 计算,函数,类型转换),否则索引失效。
d 复合索引不能使用( !=, <>, is null ,is not null) ,否则自身以及右侧所有全部失效。
- 5. 导致索引失效的如下几种情况
aaa. 尽量不要使用类型转换(显示 ,隐式),否则索引失效。
explain select * from teacher where tname="abc";
explain select * from teacher where tname=123; -- 程序底层将123 转换为“123”,即进行了类型转换 因此索引失效。
bbb. 尽量不要使用or ,否则左右两边的索引都失效。
explain select * from teacher where tname='t' or tcid>1;
a. NOT IN 和 <> 和 != 操作都会导致索引失效,进而进行全表扫描,
not in 可以用 not exists 代替,
id<>3 可以用 id>3 or id<3 代替, ;
b. 尽量避免在where 子句中对字段进行null值判断,否则将导致引擎放弃使用索引进而进行全表扫描,如 select id from t where num is null ;
c. 应尽量避免在where 子句中 使用or 来链接条件,如果一个字段有索引, 一个字段没有索引,将导致引擎放弃使用进而扫描全表,如 select id from t where num=10 or name="admin " 替换成 select id from t where num=10 union all select id from t where name="admin" ;
d .应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:select id from t where num/2 = 100 应改为:select id from t where num = 100*2;
e.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3) = ’abc’ -–name以abc开头的id
select id from t where datediff(day,createdate,’2005-11-30′) = 0 -–‘2005-11-30’ --生成的id
应改为:
select id from t where name like 'abc%'
select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1'
f.不要在where子句中的“=”左边进行函数, 算术运算或者其他表达式运算, 否则系统将可能无法正确使用该索引
G. update语句 如果只更改 一两个字段, 不要update全部字段, 否则频繁调用会引起性能方面的性能消耗,同时带来大量的日志。
H. 对于多张大数据量的表 要先分页再JOIN
I .Select cout(*) from t ; 这样子不带任何条件的count会引起全表扫描,并且没有业务意义,一定要杜绝;
J. 任何地方都不要使用select * from t , 用具体的字段代替*, 且不要返回任何不需要的任何字段;
K. 避免频繁的创建和删除临时表, 如果一定要使用临时表,注意 要先truncate table 再 drop table 这样子可以避免长时间锁住表;
L. 避免大事务的操作,提高系统的并发能力 ;
mysql 一些其他的优化方法:
exist 和in :
select * from table where exist (子查询)
select * from table where 字段 in (子查询)
如果主查询的数据集大,则建议使用in,in 效率高 ; 如果子查询的数据集大,则建议使用exist ;
exist语法:将主查询的结果,放到子查询的结果中进行条件校验(是否有数据,如果有数据则校验成功,如果没有数据则校验失败!)
============================================================================================
如何实现 MySQL 的读写分离?MySQL 主从复制原理的是啥?如何解决 MySQL 主从同步的延时问题?
1 如何实现 MySQL 的读写分离?
其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去。
2 MySQL 主从复制原理的是啥?
主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个 IO 线程,将主库的 binlog 日志拷贝到自己本地,写入一个 relay 中继日志中。接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL,这样就可以保证自己跟主库的数据是一样的。
7 exists 和in 的区别
当外查询的数据大时,子查询中的记录较少时,用in;
先查询子句,然后把外表一条条的与已得到的查询结果匹配,这个时候子查询还会重新运行一遍;
当外查询的数据较少,子查询的记录较多时,用exists;
先对外表做loop循环, 把外表的每一行与子表的查询去匹配,相当于两个嵌套的for循环,得到了正确结果之后就返回相当于break;。
exists对外表做loop循环,in把内表外表做hash连接;
4 drop、truncate与delete分别在什么场景之下使用?
对比一下他们的区别:
drop table
1)属于DDL
2)不可回滚
3)不可带where
4)表内容和结构删除
5)删除速度快
truncate table
1)属于DDL
2)不可回滚
3)不可带where
4)表内容删除
5)删除速度快
delete from
1)属于DML
2)可回滚
3)可带where
4)表结构在,表内容要看where执行的情况
5)删除速度慢,需要逐行删除
不再需要一张表的时候,用drop
想删除部分数据行时候,用delete,并且带上where子句
保留表而删除所有数据的时候用truncate
二:mysql explian 优化sql
1 查看mysql 的版本 ,先进入mysql 然后输入linux命令:mysql -V
2 查询数据库引擎,查看mysql数据支持哪种引擎:
show engines
3 查看当前使用的引擎:
show variables like '%storage_engine%';
mysql引擎: innoDB 事务优先 (适合高并发操作,行锁);
myISAM: 性能优先(表锁)
1. mysql 结构:
2 SQL优化的原因:
性能低 执行时间长 等待时间长;
sql语句欠佳(链接查询)索引失效,服务器参数设置不合理(比如缓冲区 线程数)
3-1 索引的弊端:
索引本身很大 可以存放在内存/硬盘中;
索引不是所有情况均适用,(少量数据 ,频繁改动的数据,很少使用的字段);
索引会降低增删改的效率;
3-2 索引的优势:
提高查询的效率(提高了io使用率);
降低cpu的效率(b树索引本身就是排好序的);
二层B数
三层B数
4 索引的分类:
单一索引:选择一个表中的单列作为索引,比如name;
主键索引:特点是不能重复,不能为null
唯一索引:特点是不能重复,可以为null;比如选择id作为索引;
复合索引:选择一个表中的多个列作为索引,比如选择 name+sex 作为索引;(如果用name 就可以查询唯一的值,就不需要第二步再用sex,这两个索引不是一定要全部用上的)
4 -1 创建索引的第1种方式:create 索引类型 索引名 on 表名(字段名)
单一索引 create index dept_index on tb (dept);
唯一索引:create unique index name_index on tb(name);
复合索引:create index dept_name_index on tb(dept,name);
4 -2创建索引的第2种方式: alter table 表名 add 索引类型 索引名 (字段)
单值索引: alter table tt add index dept_index (dept);
唯一索引: alter table tt add unique index name_index (name);
复合索引: alter table tt add index dept_name_index (dept,name);
4 -3删除索引: drop index 索引名 on 表名
drop index dept_index on tt
4 -4查看索引: show index from tt;
查询的时候:
ID相同的时候,表中的数据少的 先执行,其他依次。
ID不同的时候,ID值越大 越优先查询(本质 在嵌套子查询时,先查内层 再查外层)。
ID有相同 有不同的时候: ID值越大的越优先, ID值相同的,表中数据少的先执行。
(1)select_type(查询类型):
- PRIMARY: 包含子查询sql中的主查询(最外层);
- SUBQUERY : 包含子查询sql中的子查询(非最外层);
- simple :简单查询(不包含子查询 , union);
- derived : 衍生查询(使用到了临时表)
(1) . 在from 子查询中 只有一张表.
explain select cr.cname from ( select * from course where cid in (1, 2 ) ) as cr ;
(2). 在from子查询中,如果有 表1 union 表2 ,则表1 就是derived .
explain select cr.cname from ( select * from course where cid in (1) union select * from course where cid in (2) ) as cr ;
union
(2)type (索引类型) :
system > const >eq_ref > ref >range >index >all (优化级别)
要对索引进行优化前提是有索引;
- system 忽略;
- const 仅能查到一条数据的sql,用于primary key 或 unique 索引 ;
- eq_ref 唯一索引:对于每个索引键的查询,返回匹配唯一一行数据(有且只有一个 不能多 不能0)
一般只能达到range 或者 ref ,如果不 优化就是 all .
- ref 非唯一性索引: 对于每个索引键的查询,返回匹配的所有行(0 ,多)。
- range 检索指定范围的行, where 后面是一个范围查询( between , > < > =, in有时候会失效)。
- index 查询全部索引中数据。
- all 查询全部表中的数据。
(3)possible_keys 可能用到的索引 ,是一种预测 不准。
(4)key 实际使用到的索引。
(如果possible_keys/key 值为null 这是没有用到索引)
(5)key_len 索引的长度 :用于判断复合索引是否完全被使用。
utf8 1个字符3个字节
gbk1个字符2个字节
latin. 1个字符 1个字节
(6)ref 指明当前表所参照的字段
(7)rows : 被索引优化查询的 数据个数(实际通过索引而查询到的数据个数)
(8)Extra :
using filesort 性能消耗大 需要额外的一次排序(查询)
where 和order by 不要夸列使用索引的序号是连着一起的;
create table test02 (
a1 char(3),
a2 char(3),
a3 char(3),
index index_a1(a1),
index index_a2(a2),
index index_a3(a3)
);
explain select * from test02 where a1="" order by a2 ; --using filesort
对于单索引来说 如果排序和查找是同一个字段则不会出现 ,反之则会出现using filesort;
避免的话:就where哪些字段 就order by哪些字段
复合索引: 不能夸列 (最佳左前缀)
alter table test02 add index index_a1_a2_a3 (a1, a2, a3);
explain select * from test02 where a1='' order by a3 ; -using filesort
explain select * from test02 where a2='' order by a3 ;- using filesort
explain select * from test02 where a1='' order by a2 ;
小结: where 和order by 按照复合索引的顺序使用, 不要夸列使用;
(9)using temporary 性能消耗大 用到了临时表,一般出现在group by 语句中。
避免: 查询哪些列 就根据哪些列查找;
(10)using index:性能提升, 索引覆盖(覆盖索引) 原因: 不读取原文件,只从索引文件中获取数据(不需要回表查询);
explain select a1 ,a2 from test02 where a1='' OR a2='';
如果用到了索引覆盖(using index)时,会对possible_keys 和key造成影响;
a : 如果没有where. 则索引只出现在key中;
b: 如果有where 则索引出现在key 和 possible_keys中;
(11)using where 需要回表查询
假设 age 是索引列
explain. select age, name from student where age='20 '; 此语句须回到原表中查询name字段。
(12) impossible where:
where 子句永远为false .
(13)usting join buffer :
extra 中的选项,作用: 语句写的太差 mysql 看不去了,mysql引擎使用了 链接缓存
总结:
- 如果(a, b, c, d )复合索引和使用的顺序全部一致(且不夸列使用), 则复合索引全部使用;如果部分一致(且不夸列使用),则使用部分索引。
- where 和 order by拼接起来, 不要夸列使用。
SQL优化案例 ( 多表优化)
单表优化
编写的过程:select dinstinct ..from ..join .. on .. where ..group by .. having ..order by ...
解析的过程: from ..on.. join...where ..grounp by ...having ...select dinstinct ...order by ..
索引一旦进行 升级优化, 需要将之前废弃的索引删掉,防止干扰。
小结:
a 最佳前缀 保持索引的定义和使用的顺序一致性。
b 索引需要逐步优化。
c 将含in 的范围查询 放到where条件的最后 防止失效。
多表查询时,小表驱动大表。
(索引建立在经常使用的字段上,左外链接给左表加索引,右歪链接时给右表加索引)
多表语句:t.cid=c.cid(数据小的表放在左边,给t.cid家索引)
explain select * from teacher2 as t left outer join course2 as c on t.cid=c.cid where c.cname='java';
alter table teacher2 add index index_t_cid (cid);
alter table course2 add index index_c_cname(cname);
三表查询优化 abc
- 小表驱动大表
- 索引建立在经常查询的字段上。
order by 优化:
using filesort 有两种算法: 双路排序 和单路排序(根据io的次数)
Mysql4.1 之前默认是双路排序: 扫描2次磁盘 (1. 从磁盘读取排序字段 在buffer缓冲区 进行排序 2.扫描其他字段 );
----从双路排序转为单路排序,是因为io较为消耗性能
Mysql4.1 之后默认是单路排序: 只读取一次全部字段, 在buffer缓冲区 进行排序。但是有隐患,就是不一定是真的单路,有可能读取多次。原因是因为如果数据量特别大,则无法将所有字段一次性读取完毕,因此会进行'分片读取,多次读取'.
注意:
单路排序比双路排序会占用更多的buffer;
单路排序在使用时,如果数据特别大,可以考虑调整buffer的容量大小(set max_length_for_sort_data=1024 单位字节byte );
如果max_length_for_sort_data的值太小 ,mysql 会自动从单路---切换到--->双路(太低:需要排序的列的总大小超过了max_length_for_sort_data 定义的字节数).
提升order by 查询的策略:
a: 选择使用单路 ,双路,或着调整buffer的容量大小;
b:避免用select * from ...., 换成select a, b, c, from ......
c:复合索引,不要夸列使用,避免using filesort
d: 保证全部的排序字段, 排序的一致性(比如涉及的字段都是升序 或降序,不建议有的字段升序 ,有的字段降序)
sql 排查 -慢查询日志: mysql提供的一种日志记录,用于记录mysql中响应时间超过阀值的sql语句(long_query_time 默认10秒)。
慢查询日志默认是关闭的,建议开发调优时打开,而最终部署时关闭。
检查是否开启了慢查询日志: show variables like '%slow_query_log%';
临时开启 (mysql 退出服务器关闭就关闭了):
set global slow_query_log=1 ;(内存中开启)
exit 退出mysql
service mysql restart ;
永久开启: /etc/my.cnf 中追加配置
vim /etc/my.cnf (在mysqld中尾部写的)
#永久开启mysql慢查询日志
slow_query_log=1
slow_query_log_file=/var/lib/mysql/localhost-slow.log
查询慢查询阀值: show variables like '%long_query_time%';
临时设置慢查询阀值:
set global long_query_time=5; --设置完毕后 重新登录后生效
永久设置慢查询阀值: /etc/my.cnf 中追加配置
vim /etc/my.cnf (在mysqld中尾部写的): long_query_time=3
select sleep(6); 休眠6秒
查询超过阀值的sql: show global status like '%slow_queries%';
1 慢查询的sql 被记录在了日志中,因此可以通过日志查看具体的慢sql.
cat /var/lib/mysql/localhost-slow.log;
2 通过mysqldumpslow工具查询慢sql
mysqldumpslow--help;
==============================================================================
三 .大表优化
当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
1. 限定数据的范围
务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
2. 读/写分离
经典的数据库拆分方案,主库负责写,从库负责读;
3. 垂直分区
根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 如下图所示,这样来说大家应该就更容易理解了。
垂直拆分的优点: 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
4. 水平分区
保持数据表结构不变,通过某种策略存储数据分片。****这样每一片数据分散到不同的表或者库中,达到了分布式的目的。****水平拆分可以支撑非常大的数据量。
水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。
水平拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库 。
水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨节点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
-- in 用法
select a.* from t_resource_reconcile_summary as a where a.row_id in
(select b.row_id from t_resource_reconcile_summary as b where b.cost_region = "cn" );
-- exists用法
select a.* from t_resource_reconcile_summary as a where exists
(select 1 from t_resource_reconcile_summary as b where b.cost_region = "cn" and a.row_id =b.row_id );
-- exists用法
select a.* from t_resource_reconcile_summary as a where exists
(select 1 from t_resource_reconcile_summary as b where b.cost_region = "cn" and a.row_id =b.row_id and exists
(select 1 from t_resource_reconcile_summary as c where c.period = "202112" and c.row_id =b.row_id) );