影响程序慢的原因总结:
1、数据库数据量大
2、查询sql脚本写的有问题
3、程序锁表,并发用户
4、数据包的影响
5、网络带宽,数据包流量
6、CPU
7、内存
8、磁盘IO,磁头转速
第一、考虑数据库的 I/O 性能,
第二、考虑 CPU 计算、内存使用情况等
IO瓶颈
1,磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询都会产生大量的IO,降低查询的速度 分库 垂直分表
2,网络IO瓶颈,请求的数据太多,网络带宽不够 分库
CPU瓶颈
1,SQL问题,如SQL中包含JOIN,GROUP BY,ORDER BY,非索引字段条件查询等,增加CPU运行的操作,SQL优化,建立合适的索引,在业务层进行业务运算
2,单表数据量太大,查询时扫描的行太多,SQL效率低,增加CPU运行的操作。水平分表
1,磁盘读IO瓶颈,热点数据太多,数据库缓存放不下,每次查询都会产生大量的IO,降低查询的速度 分库 垂直分表
2,网络IO瓶颈,请求的数据太多,网络带宽不够 分库
CPU瓶颈
1,SQL问题,如SQL中包含JOIN,GROUP BY,ORDER BY,非索引字段条件查询等,增加CPU运行的操作,SQL优化,建立合适的索引,在业务层进行业务运算
2,单表数据量太大,查询时扫描的行太多,SQL效率低,增加CPU运行的操作。水平分表
分库分表的要求:阿里开发操作手册。如果一张表的数据大于500万或者是2G则在系统设计上就应该考虑分库分表。
分库
将数据大的表,进行分库处理
1、取余【主键ID的值除以2是否有余数,也就是说将数据按照奇偶进行划分】。优点:均匀分布数据。缺点:扩容非常不方便
2、按照范围【时间、地区、热点字段与非热点字段(根据业务的实际情况进行划分)】划分。优点:比较好扩容发。缺点:数据分布不均匀
分表
垂直分表:将一张表的字段按照热字段和冷字段进行分表。
水平分表:将一张表的数据进行上下拆分。
https://www.cnblogs.com/HDK2016/p/13522507.html
SQL执行慢:
数据库的sql语句层面
一、查询是否命中索引
二、排除多余字段,只取所需字段
1.坚决不使用“ * ”来写查询。
2.减少表之间的关联
3.优化sql,尽量让sql很快定位数据,不要让sql做全表查询,应该走索引,把数据量大的表排在前面 ,简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据
4.尽量用PreparedStatement来查询,不要用Statement
5.不使用in not in,而是使用exists 和not exists替代。in(1,2,3) 对于连续的数值,能用between就不要用in了。
6.最好不要用like查询
7.where后面最好不要跟函数操作
8.建索引,符合场景的索引
9.数据库分区
10.只查询一条数据的时候,使用limit 1
11.order by 排序优化 (排序时,使用有索引的字段进行排序)
12.读写分离,将读表独立开来。将一张表的数据,通过关联,分为读表和写表。
RANK(),排序相同的则是122
1、查询SQL尽量不要使用select *,而是select具体字段。
2、如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1
使用or可能会使索引失效,从而全表扫描。
对于or+没有索引的age这种情况,假设它走了userId的索引,但是走到age查询条件时,它还得全表扫描,也就是需要三步过程:全表扫描+索引扫描+合并 如果它一开始就走全表扫描,直接一遍扫描就完事。mysql是有优化器的,处于效率与成本考虑,遇到or条件,索引可能失效,看起来也合情合理。
假设现在需要查询userid为1或者年龄为18岁的用户,很容易有以下SQL
反例:
select* from user where userid=1or age =18
正例:
- //使用union all
- select* from user where userid=1
- union all
- select* from user where age = 18
- //或者分开两条sql写:
- select* from user where userid=1
- select* from user where age = 18
5、优化你的like语句
把%放前面,并不走索引,把% 放关键字后面,还是会走索引的
6、使用where条件限定要查询的数据,避免返回多余的行
需要什么数据,就去查什么数据,避免返回不必要的数据,节省开销。
7、尽量避免在索引列上使用mysql的内置函数
索引列上使用mysql的内置函数,索引失效.如果索引列不加内置函数,索引还是会走的。
8、应尽量避免在where子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫
反例:
select* from user where age-1=10;
正例:
select* from user where age =11;
理由:
- 虽然age加了索引,但是因为对它进行运算,索引直接迷路了。。。
9、Inner join 、left join、right join,优先使用Inner join,如果是left join,左边表结果尽量小
- Inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集
- left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。
- right join 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。
都满足SQL需求的前提下,推荐优先使用Inner join(内连接),如果要使用left join,左边表数据结果尽量小,如果有条件的尽量放到左边处理。
10、应尽量避免在where子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
反例:
select age,name from user where age <>18;
正例:
- //可以考虑分开两条sql写
- select age,name from user where age <18;
- select age,name from user where age >18;
理由:
- 使用!=和<>很可能会让索引失效
15、慎用distinct关键字
distinct 关键字一般用来过滤重复记录,以返回不重复的记录。在查询一个字段或者很少字段的情况下使用时,给查询带来优化效果。但是在字段很多的时候使用,却会大大降低查询效率。
带distinct的语句cpu时间和占用时间都高于不带distinct的语句。因为当查询很多字段时,如果使用distinct,数据库引擎就会对数据进行比较,过滤掉重复数据,然而这个比较、过滤的过程会占用系统资源,cpu时间。
17、如果数据量较大,优化你的修改/删除语句。
一次性删除太多数据,可能会有lock wait timeout exceed的错误,所以建议分批操作。
inndb引擎的使用如下 (MyIASM默认存了数据总数,所以效率最高)
1:count(字段):遍历整张表 会把每一行的字段值取出来,然后返回
2:count(1): 便利整张表,但不取值,对于返回的数据,放入1进去.然后累加
3:count(*):inndb引擎,特意做了优化,不会取出值,直接服务层进行累加、
13.update优化 (避免出现表锁)
innodb引擎使用update时,会有行锁/表锁两种模式, 如果where 字段没有索引的时候会升级成表锁,
程序应用层面
1、静态类设计(1、页面的查询使用List<>,将数据取到程序中处理。2、基础数据使用字典类缓存)
2、数据库设计(1、业务库。2、系统库。3、第三方库(接口中间库))
3、日常注意(1、查询不适用*。2、使用limit)
将一个大量的数据库转存到另一种表。将数据分成段,第二多线程跑
Hi,
Tomorrow!