本文主旨:从现有的软件和硬件配置中获得最佳的数据库性能。
优化思路:
InnoDB
表的所有工作负载以及只读 MyISAM
表。InnoDB
存储引擎处理大部分锁定问题,不需要人为参与,允许在数据库更好的并发。 、InnoDB
缓冲池,MyISAM
键高速缓存和MySQL查询高速缓存。show processlist;
id列:一个标识,你要kill 一个语句的时候很有用。
command列:显示当前连接的执行的命令,一般就是休眠(sleep),查询(query),连接(connect)。
time列:此这个状态持续的时间,单位是秒。
state只是语句执行中的某一个状态,是判断性能好坏的关键.
state 如果出现如下内容,则该行记录的 SQL 语句需要优化:
create tmp table -- 创建临时表, 索引及现有结构无法涵盖查询条件,才会建立一个临时表来满足查询要求
copying to tmp table on disk 把内存临时表复制到磁盘
locked 被其他查询锁住
loggin slow query 慢查询记录
sorting result 排序
MySQL通过慢查询日志定位那些执行效率较低的SQL 语句,通常意义上来讲,只要返回时间大于 >1 sec上的查询都可以称为慢查询。慢查询会导致CPU,内存消耗过高。
-- long_query_time 当SQL语句执行时间超过此数值时,就会被记录到日志中
-- 默认如图,建议设置为1或者更短。
show variables like 'long%'; -- 查询
set long_query_time=1; -- 设值
-- slow_query_log 这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句。
-- slow_query_log_file 记录日志的文件名。
-- slow_query_log变量被设置为ON,MySQL会立即开始记录。
show variables like 'slow%'; -- 查询
set global slow_query_log='on'; -- 设值
用--log-slow-queries[=file_name]选项启动时,mysqld 会写一个包含所有执行时间超过 long_query_time 秒的SQL语句的日志文件 。
修改完配置信息后,通过 show variables like 'long%'; show variables like 'slow%'; 两条命令看配置是否生效。
MySQL在Windows系统中的配置文件一般是是my.ini找到[mysqld]下面加
查找my.ini位置,可通过windows服务所对应mysql启动项,查看其对应属性->可执行文件路径,获取my.ini路径。
更改后重启mysql服务生效
-- 设置日志位置及文件名
log_slow_queries = F:/MySQL/log/mysqlslowquery.log
long_query_time = 1
-- MySQL5.7
-- 默认情况下,将禁用慢速查询日志。要显式指定初始慢速查询日志状态
-- 如果没有参数或参数为1,--slow_query_log将启用日志。
-- 参数为0时,此选项将禁用日志。
slow_query_log[={0 | 1}]
-- 指定日志文件名
slow_query_log_file=file_name
MySQL在Linux系统中的配置文件一般是是my.cnf找到[mysqld]下面加上
-- 设置日志文件位置及文件名
log slow queries = /data/mysqldata/slowquery.log
long_query_time = 1
我们可以使用 mysqldumpslow --help 查看命令相关用法。(windows安装MySQL默认不安装一些插件,需要先配置Perl 环境,好难一年之内都没有大佬写这个文. . . . . .)
参数如下:
-s:排序方式,后边接着如下参数
c:访问次数
l:锁定时间
r:返回记录
t:查询时间
al:平均锁定时间
ar:平均返回记录书
at:平均查询时间
-t:返回前面多少条的数据
-g:搭配一个正则表达式,大小写不敏感
案例:
-- 得到返回记录最多的10个sql
mysqldumpslow -s r -t 10 slow.log
-- 得到平均访问次数最多的10条sql
mysqldumpslow -s ar -t 10 slow.log
-- 得到平均访问次数最多,并且里面含有user字符的20条sql
mysqldumpslow -s ar -t 20 -g "user" slow.log
查看 SQL 执行计划情况(关联表,表查询顺序、索引使用情况等)。
为了避免本文太长,指路 2.5 explain 查看索引是否生效 https://blog.csdn.net/wuyanwenyun/article/details/105575807
使用 profiling 命令可以了解 SQL 语句消耗资源的详细信息(每个执行步骤的开销)。
-- 查看 profile 开启情况
-- 0 表示关闭状态,1 表示开启
select @@profiling;
-- 启用 profile
set profiling = 1;
-- 注意 :在连接关闭后,profiling 状态自动设置为关闭状态。
-- 查看执行的 SQL 列表
show profiles;
-- 查询指定 ID 的执行详细信息
-- 每行都是状态变化的过程以及它们持续的时间。
-- Status 这一列和 show processlist 的 State 是一致的。
-- 注意点与上文描述的一样 3.1 查看运行的进程。
show profile for query Query_ID;
-- 获取 CPU、 Block IO 等信息
show profile block io,cpu for query Query_ID;
show profile cpu,block io,memory,swaps,context switches,source for query Query_ID;
show profile all for query Query_ID;
1) 避免 SELECT *,需要什么数据,就查询对应的字段。
2) 小表驱动大表,即小的数据集驱动大的数据集。如:以 A,B 两表为例,两表通过 id 字段进行关联。
当 B 表的数据集小于 A 表时,用 in 优化 exist;使用 in ,两表执行顺序是先查 B 表,再查 A 表
select * from A where id in (select id from B)
当 A 表的数据集小于 B 表时,用 exist 优化 in;使用 exists,两表执行顺序是先查 A 表,再查 B 表
select * from A where exists (select 1 from B where B.id = A.id)
3) 一些情况下,可以使用连接代替子查询,因为使用 join,MySQL 不会在内存中创建临时表。左连接性能取决于左表, 右连接取决于右表。
4) 对于频繁操作的数据,可适当添加冗余字段,减少表关联。反第三范式做法。
5) 在使用group by 分组查询时,默认分组后,还会排序,可能会降低速度,在group by 后面增加 order by null 就可以防止排序。
指路 : 2 索引 https://blog.csdn.net/wuyanwenyun/article/details/105575807
1) 使用可以存下数据最小的数据类型
2) 使用简单的数据类型。int 要比 varchar 类型在 MySQL 处理简单
3) 尽量使用 tinyint、smallint、mediumint 作为整数类型而非 int
4) 尽可能使用 not null 定义字段,因为 null 占用4字节空间
5) 尽量少用 text 类型,非用不可时最好考虑分表
6) 尽量使用 timestamp 而非 datetime
7) 单表不要有太多字段,建议在 20 以内
大表的优化!!!在完成以上优化后,考虑表的拆分。 让每张表的数据量变小,从而提高查询效率。
为什么要分表?
(1) 如果一个表的每条记录的内容很大,那么就需要更多的IO操作,如果字段值比较大,而使用频率相对比较低,可以将大字段移到另一张表中,当查询不查大字段的时候,这样就减少了I/O操作
(2)如果表的数据量非常非常大,那么查询就变的比较慢;也就是表的数据量影响这查询的性能。
(3)表中的数据本来就有独立性,例如分别记录各个地区的数据或者不同时期的数据,特别是有些数据常用,而另外一些数据不常用。
1)垂直拆分
将表中多个列分开放到不同的表中。例如用户表中一些字段经常被访问,将这些字段放在一张表中,另外一些不常用的字段放在另一张表中,分离冷热数据。插入数据时,使用事务确保两张表的数据一致性。
垂直拆分的优点:可以使得每一条数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
垂直拆分的缺点:主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂。
2) 水平拆分
按照行进行拆分。例如用户表中,使用用户ID,对用户ID取10的余数,将用户数据均匀的分配到0~9的10个用户表中。查找时也按照这个规则查询数据。水平分表尽可能使每张表的数据量相当,比较均匀。
水平分割最重要的是找到分割的标准,不同的表应根据业务找出不同的标准
用户表可以根据用户的手机号段进行分割如user183、user150、user153、user189等,每个号段就是一张表
用户表也可以根据用户的 id 进行分割,加入分3张表user0,user1,user2,如果用户的id%3=0就查询user0表,
如果用户的id%3=1就查询user1表对于订单表可以按照订单的时间进行分表
一般情况下对数据库而言都是“读多写少”。数据库的压力多数是因为大量的读取数据的操作造成的。我们可以采用数据库集群的方案,使用一个库作为主库,负责写入数据;其他库为从库,负责读取数据。这样可以缓解对数据库的访问压力。
读写分离就是只在主服务器上写,只在从服务器上读。基本原理是让主数据库处理事务性查询,而从服务器处理select查询。数据库复制被用来把事务性查询导致的变更同步到从数据库中。
实现MySQL读写分离的前提是我们已经将MySQL主从复制配置完毕,读写分离实现方式:
(1)配置多数据源。
(2)使用 MySQL 的 proxy 中间件代理工具。