1 概念
性能优化是通过某些有效的方法提高 mysql 数据库的性能。性能优化的目的是为了 mysql 数据运行速度更快、占用的磁盘空间更小。性能优化包括很多方面,例如硬件(随机磁盘阵列)、系统配置(mysql缓存、文件打开数量等)、数据库表结构(范式、水平、垂直等)、SQL及索引(分析、优化等)等,这里主要介绍SQL及索引和数据库表结构。
2 SQL语句优化
2.1 慢查询
(1) 慢查询设置
查看慢查询的相关信息
(2) 慢查询日志格式
2.2 分析语句查询
可以使用 explain 和 describe 语句来分析查询语句。
(1) explain语法结构:explain select 语句;
实例:
explain select * from T_LOG_DESC_SAMPLE;
(1) rows 显示查询的行数。
(2) type 显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
(a) system
表仅有一行,这是const类型的特列,平时不会出现,这个也可以忽略不计。
(b) const
表最多有一个匹配行,const用于比较primary key 或者unique索引。因为只匹配一行数据,所以很快。记住一定是用到primary key 或者unique,并且只检索出一条数据的 情况下才会是const,看下面这条语句
虽然只搜索一条数据,但是因为没有用到指定的索引,所以不会使用const.继续看下面这个
nlogdescid是主键,所以使用了const。所以说可以理解为const是最优化的。
(c) all
进行完整的表扫描。通常可以增加更多的索引而不要使用ALL。
(3) Extra
filesort(内部排序) 和 tempory(临时表) 一般是没有索引的排序产生的。常见于order by 、group by 、 distinct。
没有索引的排序查询
2.4 常见优化查询
第一, 建立合适的索引,尽量避免全盘扫描
索引对查询结果进行排序,没索引将会采用内部文件排序算法进行排序,效率较慢。
第二,子查询优化
查询优化器对子查询一般采用嵌套执行的方式,即对父查询中的每一行,都执行一次子查询,这样子查询会执行很多次。这种执行方式效率很低。在多表连接查询考虑连接代价再选择(往往连接更有效率一些,是因为 mysql 不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作)。
第三,外连接优化
外连接转化为内连接(优化处理器处理外连接比内连接步骤多且耗时)。
备注:
(a) 内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现。
(b) 外连接: 左外连接(左边的表不加限制) 、右外连接(右边的表不加限制) 、全外连接(左右两表都不加限制)。
(c) 自连接(连接发生在一张基表内)。
具体优化:
(1). 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
(2). 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。(注意:主键支持。非主键不支持)
(3). 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
(4). 应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
(5). 下面的查询(将%放到开头)也将导致全表扫描:
select id from t where name like '%abc%'
若要提高效率,可以考虑全文检索,尽量不要把 % 放开头。
(6). in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
(7). 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100
应改为:
select id from t where num=100*2
(8). 应尽量避免在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'
(9). 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
(10). 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
(11). 很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select * from b where num=a.num)
(12). 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
(13). 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
(14). 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
(15). 尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
(16). 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
3 数据库结构优化
3.1 选择合适的数据类型
(1) 时间存储
(2) ip地址
3.2 范式和非范式
三大范式:
(1) 第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值。
(2) 第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。
(3) 第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
3.2.1 范式化优化
3.2.2 反范式化优化
3.3 垂直拆分
把主码和一些列放到一个表,然后把主码和另外的列放到另一个表中。如果一个表中某些列常用,而另外一些列不常用,则可以采用垂直分割,另外垂直分割可以使得数据行变小,一个数据页就能存放更多的数据,在查询时就会减少I/O 次数。其缺点是需要管理冗余列,查询所有数据需要join操作。
(1) 如何拆分
(2) 拆分实例
3.4 水平拆分
通过hash值进行分表
本文参考:
http://www.imooc.com/learn/194