许多不同的硬件都可能会影响都MySQL的性能,例如操作系统,磁盘大小,可用内存,CPU,网络以及各种计算机组件,最常见的瓶颈就是CPU/IO资源。
当数据可以放在内存中或者可以从磁盘中以足够快的速度读取时,CPU可能出现瓶颈;
另外,IO瓶颈,一般发生在工作所需的数据远远超过有效内存容量的时候。
默认情况先MySQL的查询缓存是开启的,MySql8.0之后默认关闭了缓存的功能
//查询缓存
show variables like '%query_cache%';
//查询缓存命中率
show status like 'Qcache%';
//查询缓存的总个数
show status like 'Com_select';
//结果集缓存
show variables like 'net_buffer_length';
show variables like 'max_allowed_packet';
//排序缓存
show variables like '%sort%';
//表缓存
show variables like 'table%';
//所有缓存
show variables like 'key%';
//日志缓存
show variables like '%binlog%cache%';
当然除了,MySQL服务自带的缓存机制,还可以借助外部的缓存,例如redis,Memcached等等
重用的数据库连接池有c3p0,dbcp,druid,Hikari,本身数据库的连接就需要占用资源,需要不断的建立连接,关闭连接,那么有了连接池之后,就可以连接复用,减少资源的消耗
数据量非常庞大上千万级数据量时,可以考虑读写分离,只从复制,读库远远比写库多的情况下(一般读写比至少大于9:1),为了缓解主库的压力,将大多数读请求压力均摊到多个从库上。
随着数据库业务的不断增长,数据库表里面的数据可能会越来越多,那么势必会造成查询的速度变慢,增删改查的开销也会越来越大,数据库的读写性能可能会成为业务发展的瓶颈。那么就可以把原本存储到一个库的数据分别存储到多个库上,把原本存储到一个表的数据分别存储到多个表上。
还比如,订单表一年下来可能要一个表要存上百万的数据量,那么就可以把这个订单表进行拆分,例如可以按时间维度进行拆分,一年存一个订单表,下一年度的重新存一个订单表
一般200毫秒到300毫秒之内可以接受,超过这个时间就会是慢sql
show variables like 'slow_query%';
慢sql 默认是关闭的
set global slow_query_log=1
想要永久开启慢查询需要去my.in.cfg里面去修改配置文件
slow_query_log = 1
slow_query_log_file = /tmp/mysql_slow.log
可以借助mysqldumpslow日志分析工具来分析慢日志,找到那些慢sql 进行优化
针对那些慢查询,去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,这是我们需要用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。
expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、extra
select_type
(1) SIMPLE(简单SELECT,不使用UNION或子查询等)
(2) PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
(3) UNION(UNION中的第二个或后面的SELECT语句)
(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
(5) UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select)
(6) SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询)
(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询)
(8) DERIVED(派生表的SELECT, FROM子句的子查询)
(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
type
常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)
ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
index: Full Index Scan,index与ALL区别为index类型只遍历索引树
range:只检索给定范围的行,使用一个索引来选择行
ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
良好的数据库设计能够减少数据冗余、降低数据库维护的成本、节约空间、高效访问,反之就会存在大量的数据冗余,存在数据插入、删除、更新异常,浪费大量的存储空间,访问效率低。
那么除了要遵守数据库设计的三大范式原则,还需要有字段的设计,索引的设计,主键外键的设计等等,这些都会影响到数据库的性能
整型类型的选择,例如整型类型就有5中,分别是tinyint,smallint,mediumint,int,bigint,这些类型都会占用存储长度,选择合适的类型进行存储可以减少冗余和磁盘空间;
还比如 时间类型的选择,时间类型也有好几种,有日期,时间,时间戳,年,时分秒,每个类型的长度也不一样
char 和 varchar 的选择
char的长度是固定的255个字符,如果插入的长度小于定义长度时,则用空格填充
varchar 是可变的,根据存的字符长度来变化
正是由于char的长度是固定的,所有他的查询插入的效率要比varchar 高一些,有利也有弊
ENUM
存状态数据可以用ENUM类型,例如性别字段,国籍字段,名族字段等等,这样就不用存varchar了,大大减少了空间的开销
索引的设计
这个就根据实际的业务情况来决定,具体需要用到哪些查询索引,根据业务来添加索引
还有就是选择合适的存储引擎,支持事物选择innodb,纯读,或者纯写选择myisam
不要使用select *,取出全部列,会让优化器无法完成索引覆盖扫描这类优化,还会带来额外的IO,内存和CPU的消耗;当然select * 也有个好处就是,在添加或删减字段不会对select * 有影响
包含NULL值的列不会被创建索引,所以where中is null 或者is not null都不会走索引
like查询中,如果%like%会造成全表扫描,但是如果是like%,就会命中索引
exists替代in,not in是效率比较低,因为要对子查询的表进行全表扫描
union代替or,索引列上的or操作会造成索引失效,全表扫描
当只要一行数据时使用LIMIT1
order by子句中不要使用非索引列或嵌套表达式,这样都会导致性能降低
join 条件中把关联的字段加上索引
永远为每张表设置一个ID
where中避免使用!= > < 表达式,否则索引失效,全表扫描
尽量避免where num/2 = 10这样的查询,改为where num = 10/2,就会走索引
索引并不是越多越好,过多的索引会造成写数据时效率变低
例如限流,降级,负载均衡,队列,分布式等等
————————————————
版权声明:本文为CSDN博主「珍妮玛•黛金」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/woshiwangdaye/article/details/118966401