MySQL优化&慢查询
目录
1. MySQL优化
1. 存储引擎的选择:INnoDB MyISAM
什么是存储引擎?
数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作。不同的存储引擎提供不同的存储机制、
索引技巧、锁定水平等功能,使用不同的存储引擎还可以获得特定的功能。
现在许多数据库管理系统都支持多种不同的存储引擎。MySQL 的核心就是存储引擎。
InnoDB事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。MySQL 5.5.5 之后,InnoDB 作为默认存储引擎。
MyISAM 是基于 ISAM 的存储引擎,并对其进行扩展,是在 Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM 拥有较高的插入、查询速度,但不支持事务。
不同的存储引擎都有各自的特点,以适应不同的需求,如表所示。为了做出选择,首先要考虑每一个存储引擎提供了哪些不同的功能。
功能 MyISAM InnoDB
存储限制 256TB 64TB
支持事务 不支持 支持
支持全文索引 支持 不支持
支持树索引 支持 支持
支持数据缓存 不支持 支持
支持外键 不支持 支持
如何选择?
如果要提供提交、回滚和恢复的事务安全(ACID 兼容)能力,并要求实现并发控制,InnoDB 是一个很好的选择。
如果数据表主要用来插入和查询记录,则 MyISAM 引擎提供较高的处理效率。
提示:使用哪一种引擎要根据需要灵活选择,一个数据库中多个表可以使用不同的引擎以满足各种性能和实际需求。使用合适的存储引擎将会提高整个数据库的性能。
2. 设计数据库的设计,尽量的遵循三范式?
第一范式1NF(确保每列都保持原子性)
即表的列的具有原子性,不可再分解,只要数据库是关系型数据库就自动的满足1NF。数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。如果实体中的某个属性有多个值时,必须拆分为不同的属性 。通俗理解即一个字段只存储一项信息。
温馨提示:
关系型数据库特点:面向对象或者集合
非关系型数据库特点:面向文档
第二范式2NF(确保表中每列都和主键直接相关)
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要我们设计一个主键来实现(这里的主键不包含业务逻辑)。
即满足第一范式前提,当存在多个主键的时候,才会发生不符合第二范式的情况。比如有两个主键,不能存在这样的属性,它只依赖于其中一个主键,这就是不符合第二范式。通俗理解是任意一个字段都只依赖表中的同一个字段。(涉及到表的拆分)
第三范式3NF(确保表中每列都和主键列直接相关,而不是间接相关)
满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主键字段。就是说,表的信息,如果能够被推导出来,就不应该单独的设计一个字段来存放(能尽量外键join就用外键join)。很多时候,我们为了满足第三范式往往会把一张表分成多张表。
即满足第二范式前提,如果某一属性依赖于其他非主键属性,而其他非主键属性又依赖于主键,那么这个属性就是间接依赖于主键,这被称作传递依赖于主属性。 通俗解释就是一张表最多只存两层同类型信息。
反三范式
没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,提高读性能,就必须降低范式标准,适当保留冗余数据。具体做法是: 在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,减少了查询时的关联,提高查询效率,因为在数据库的操作中查询的比例要远远大于DML的比例。但是反范式化一定要适度,并且在原本已满足三范式的基础上再做调整的。
3. 适当的建立索引
什么是索引?
关键字与数据的映射关系称为索引(包含关键字和对应的记录在磁盘中的地址)。关键字是从数据当中提取的用于标识、检索数据的特定内容。
索引的类型?
主键索引:
要求关键字唯一且不为 bull
普通索引:
按照第一字段有序
唯一索引:
关键字的唯一
全文索引:
所有数据都要有索引
什么情况下说明你需要建立索引了?
1.明明数据量不大,百万级以下,数据库查询速度过慢。
2.用了数据库线程池但还是会爆掉。
相关报错举例:
A. Could not get JDBC Connection.无法获得JDBC连接
B. Cannot get a connection, pool error Timeout waiting for idle object.池错误超时等待空闲对象
小常识:
索引是给表建立了一个字典目录,根据目录查询数据库会很快。索引是数据库查询时自动辨别使用的。
(对于字符串类型字段,若在WHERE中使用LIKE进行过滤时,是不会用到索引的。)
如何添加索引?
1.可以使用工具添加,比如:sqlyog中选择表右键“管理索引”即可。
2.执行sql建立索引。
举例:ALTER TABLE 库名.表名 ADD INDEX idx_couponsCode (coupons_Code);
其中idx_couponsCode为索引名,可以自定义,coupons_Code为表中字段名。
如何使用索引?(使用原则)
1、较频繁的作为查询条件字段应该创建索引
select * from emp where empno = 1;
2、唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
select * from emp where sex = ‘男’
3、更新非常频繁的字段不适合创建索引
select * from emp where logincount = 1
4、不会出现在WHERE子句中的字段不该创建索引
怎样验证数据库查询是否使用了索引?
EXPLAIN关键字
使用方式,EXPLAIN+SQL语句即可.
我们只需要注意一个最重要的type 的信息很明显的提现是否用到索引:
type结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。
possible_keys:sql所用到的索引
key:显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL
rows: 显示MySQL认为它执行查询时必须检查的行数。
4. 尽量采用 贵的,SSD硬盘。不选择机械硬盘
5. 数据量大的时候,主从分离、分库分表、垂直/水平分割
mysql一主多从,读写分离:写主库,读从库(所有数据库的数据一样)
缺点
数据一样的,那么当数据量太大的时候查询还是很慢
分库(根据用户id分库)
所有数据库的表结构一样,存储的数据完全不一样
真实环境以用户id进行分库,每一个库的数据都很小,查询起来就快了
分表(根据时间分表)
当一个表中数据过大的时候,我们必须要对表拆分
购物清单表中有两千万数据
最近半年的购物数据时 一百万
半年到一年的数据有五百万
一年以前的数据有一千万
水平分割:通过建立结构相同的几张表分别存储数据
垂直分割:将经常一起使用的字段放在一个单独的表中,分割后的表记录之间是一一对应关系。
6. 查询数据的时候,注意事项
- 尽量避免 select *
- 尽量少 join
- 尽量少排序
- 避免类型转换
- 尽可能对每一条运行在数据库中的SQL进行 explain
2. 慢查询
1. 什么是MySQL的慢查询?
慢查询日志,顾名思义,就是查询慢的日志,是指mysql记录所有执行超过long_query_time参数设定的时间阈值的SQL语句的日志。该日志能为SQL语句的优化带来很好的帮助。默认情况下,慢查询日志是关闭的,要使用慢查询日志功能,首先要开启慢查询日志功能。
2. 如何去分析 慢查询的日志?
慢查询的日志记录非常多,要从里面找寻一条查询慢的日志并不是很容易的事情,一般来说都需要一些工具辅助才能快速定位到需要优化的SQL语句,下面介绍慢查询辅助工具:
Mysqldumpslow
常用的慢查询日志分析工具,汇总除查询条件外其他完全相同的SQL,并将分析结果按照参数中所指定的顺序输出。
语法
mysqldumpslow -s r -t 10 slow-mysql.log
-s order (c,t,l,r,at,al,ar)
c:总次数
t:总时间
l:锁的时间
r:总数据行
at,al,ar :t,l,r平均数 【例如:at = 总时间/总次数】
-t top 指定取前面几条作为结果输出
3. 遇到了慢查询如何解决?
要解决慢查询,就是优化这些查询缓慢的语句,或是重新组织自己的数据。
重新组织数据的表现形式是分表。对于成熟的业务系统而言,分表的代价是极高的。所以如何组织一张表仍然是建表的重要决策。
因此,优化语句才是解决慢查询的基本方法。
4. 索引的建立是越多越好?为什么不是越多越好?
当然不是,
关于建立索引的几个准则:
1、合理的建立索引能够加速数据读取效率,不合理的建立索引反而会拖慢数据库的响应速度。
2、索引越多,更新数据的速度越慢。
不要在选择的栏位上放置索引,这是无意义的。应该在条件选择的语句上合理的放置索引,比如where,order by。
例子:
SELECT id,title,content,cat_id FROM article WHERE cat_id = 1;
上面这个语句,你在id/title/content上放置索引是毫无意义的,对这个语句没有任何优化作用。但是如果你在外键cat_id上放置一个索引,那作用就相当大了。