Mysql 优化方案
从开发角度优化mysql,让数据库效率更高、更快。
索引优化
查看mysql状态
通过周期性观察mysql状态优化,更有利于确定mysql性能瓶颈在哪里。
通过 show status
命令观察mysql的运行状态。其中比较主要的几个:
命令格式:
show [global|session] status like ‘command‘; 默认是session: 当前会话;global: 全局会话。
show status like "up_time"; 查看mysql启动了多长时间
show status like ‘com_select‘; 查看mysql执行select的次数
show status like ‘com_delete‘; 查看mysql执行delete的次数
show status like ‘com_update‘; 查看mysql执行upate的次数
show status like ‘com_insert‘; 查看mysql执行insert的次数
show status like ‘Thread_srunning‘;有多少个连接正在工作
show status like ‘connections‘;试图连接mysql的次数
show status like ‘
Max_used_connections‘;mysql的最大连接数。经常会遇见”mysql: error 1040: too many connections”的情况,一种是访问量确实很高,mysql服务器抗不住,这个时候就要考虑增加从服务器分散读压力,另外一种情况是mysql配置文件中max_connections值过小。
show status like ‘Queries‘;一共执行了多少次查询
show status like ‘Slow_queries‘;慢查询次数
查看mysql变量
通过 show variables like ‘commond‘
命令查看mysql变量值。
show variables like ‘long_query_time‘; 查看慢查询时间。
更新变量值:set [golabl|session] ‘commond‘=value
就可以更改变量值。 退出,再登录,新变量生效。
将msyql默认慢查询时间更改为1秒。
set globsl long_query_time=1;
mysql默认的慢查询时间为10秒钟,该值需要根据项目的需要调整到合理值,以达到较好的效果
打开mysql记录慢查询日志功能
mysql默没有记录慢查询日志,需要手动开启慢查询记录功能。
通过命令开启慢查询功能: set global slow_query_log=on;
查看慢查询日志文件位置: show variables like ‘%slow%‘;
打开profile
set profiling=1; 打开profile功能。
show profiles; 查看执行记录。
show profile for query QueryID;[QueryID]在上条语句的执行结果中。
通过此条语句,可以详细的看到mysql再执行这条语句时,在各个细节上花费的时间。再通过explain 综合分析sql的不足之处。
show profile block io,cpu,memory,swaps for query Query_ID;
block io,分析IO消耗。
cpu,分析cpu消耗。
memory,分析内存消耗。
swaps,分析交互空间消耗。
这几个指标可以不写也可以多个组合在一起显示。
Mysql索引介绍
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
注:
[1]索引不是万能的!索引可以加快数据检索操作,但会使数据修改操作变慢。每修改数据记录,索引就必须刷新一次。为了在某种程序上弥补这一缺陷,许 多SQL命令都有一个DELAY_KEY_WRITE
项。这个选项的作用是暂时制止MySQL在该命令每插入一条新记录和每修改一条现有之后立刻对索引进 行刷新,对索引的刷新将等到全部记录插入/修改完毕之后再进行。在需要把许多新记录插入某个数据表的场合,DELAYKEYWRITE选项的作用将非 常明显。
[2]另外,索引还会在硬盘上占用相当大的空间。因此应该只为最经常查询和最经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内 容,为它建立索引就没有太大的实际效果。
从理论上讲,完全可以为数据表里的每个字段分别建一个索引,但MySQL把同一个数据表里的索引总数限制为16个。
- InnoDB数据表的索引
与MyISAM数据表相比,索引对InnoDB数据的重要性要大得多。在InnoDB数据表上,索引对InnoDB数据表的重要性要在得多。在 InnoDB数据表上,索引不仅会在搜索数据记录时发挥作用,还是数据行级锁定机制的苊、基础。”数据行级锁定”的意思是指在事务操作的执行过程中锁定正 在被处理的个别记录,不让其他用户进行访问。这种锁定将影响到(但不限于)SELECT…LOCK IN SHARE MODE、SELECT…FOR UPDATE命令以及INSERT、UPDATE和DELETE命令。 出于效率方面的考虑,InnoDB数据表的数据行级锁定实际发生在它们的索引上,而不是数据表自身上。显然,数据行级锁定机制只有在有关的数据表有一个合 适的索引可供锁定的时候才能发挥效力。 - 限制
如果WEHERE子句的查询条件里有不等号(WHERE coloum != …),MySQL将无法使用索引。 类似地,如果WHERE子句的查询条件里使用了函数(WHERE DAY(column) = …),MySQL也将无法使用索引。 在JOIN操作中(需要从多个数据表提取数据时),MySQL只有在主键和外键的数据类型相同时才能使用索引。 如果WHERE子句的查询条件里使用比较操作符LIKE和REGEXP,MySQL只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。比如说, 如果查询条件是LIKE ‘abc%’,MySQL将使用索引;如果查询条件是LIKE ‘%abc’,MySQL将不使用索引。 在ORDER BY操作中,MySQL只有在排序条件不是一个查询条件表达式的情况下才使用索引。(虽然如此,在涉及多个数据表查询里,即使有索引可用,那些索引在加快 ORDER BY方面也没什么作用) 如果某个数据列里包含许多重复的值,就算为它建立了索引也不会有很好的效果。比如说,如果某个数据列里包含的净是些诸如”0/1″或”Y/N”等值,就没 有必要为它创建一个索引。 - 普通索引、唯一索引和主索引
- 普通索引
普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件(WHERE column = …)或排序条件(ORDER BY column)中的数据列创建索引。只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来创建索引。 - 唯一索引
普通索引允许被索引的数据列包含重复的值。比如说,因为人有可能同名,所以同一个姓名在同一个”员工个人资料”数据表里可能出现两次或更多次。 如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。这么做的好处:一是简 化了MySQL对这个索引的管理工作,这个索引也因此而变得更有效率;二是MySQL会在有新记录插入数据表时,自动检查新记录的这个字段的值是否已经在 某个记录的这个字段里出现过了;如果是,MySQL将拒绝插入那条新记录。也就是说,唯一索引可以保证数据记录的唯一性。事实上,在许多场合,人们创建唯 一索引的目的往往不是为了提高访问速度,而只是为了避免数据出现重复。 - 主索引
在前面已经反复多次强调过:必须为主键字段创建一个索引,这个索引就是所谓的”主索引”。主索引与唯一索引的唯一区别是:前者在定义时使用的关键字是 PRIMARY而不是UNIQUE。 - 外键索引
如果为某个外键字段定义了一个外键约束条件,MySQL就会定义一个内部索引来帮助自己以最有效率的方式去管理和使用外键约束条件。 - 复合索引
索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引。这种索引的特点是MySQL可以有选择地使用一个这样的索引。如果查询操作只需要用到columnA数据列上的一个索引,就可以使 用复合索引INDEX(columnA, columnB)。不过,这种用法仅适用于在复合索引中排列在前的数据列组合。比如说,INDEX(A, B, C)可以当做A或(A, B)的索引来使用,但不能当做B、C或(B, C)的索引来使用。 - 索引的长度
在为CHAR和VARCHAR类型的数据列定义索引时,可以把索引的长度限制为一个给定的字符个数(这个数字必须小于这个字段所允许的最大字符个数)。这 么做的好处是可以生成一个尺寸比较小、检索速度却比较快的索引文件。在绝大多数应用里,数据库中的字符串数据大都以各种各样的名字为主,把索引的长度设置 为10~15个字符已经足以把搜索范围缩小到很少的几条数据记录了。 在为BLOB和TEXT类型的数据列创建索引时,必须对索引的长度做出限制;MySQL所允许的最大索引长度是255个字符。
- 普通索引
全文索引
文本字段上的普通索引只能加快对出现在字段内容最前面的字符串(也就是字段内容开头的字符)进行检索操作。如果字段里存放的是由几个、甚至是多个单词构成 的较大段文字,普通索引就没什么作用了。这种检索往往以LIKE %word%的形式出现,这对MySQL来说很复杂,如果需要处理的数据量很大,响应时间就会很长。
这类场合正是全文索引(full-text index)可以大显身手的地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份清单,查询操作将根据这份清单去检索有关的数 据记录。全文索引即可以随数据表一同创建,也可以等日后有必要时再使用下面这条命令添加: ALTER TABLE tablename ADD FULLTEXT(column1, column2)
有了全文索引,就可以用SELECT查询命令去检索那些包含着一个或多个给定单词的数据记录了。下面是这类查询命令的基本语法: SELECT * FROM tablename WHERE MATCH(column1, column2) AGAINST(‘word1′, ‘word2′, ‘word3′)
上面这条命令将把column1和column2字段里有word1、word2和word3的数据记录全部查询出来。
注解:InnoDB数据表不支持全文索引。
创建索引:
- 创建主健索引
将一个列设置为主键时,该列自动成为主键索引。
创建表时没有指定主键,使用命令alter table 表名 add primary key (列名);
添加主键。该列也自动创建主键索引。
主键索引是一种特殊的唯一索引,不允许有空值。 - 创建普通索引
create index 索引名 on 表名 (列名1,列名2,...);
- 创建全文索引
- 全文索引,主要是针对对文件,文本的检索, 比如文章, 全文索引针对MyISAM有用。
CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT (title,body) )engine=myisam charset utf8;
INSERT INTO articles (title,body) VALUES (‘MySQL Tutorial‘,‘DBMS stands for DataBase ...‘), (‘How To Use MySQL Well‘,‘After you went through a ...‘), (‘Optimizing MySQL‘,‘In this tutorial we will show ...‘), (‘1001 MySQL Tricks‘,‘1. Never run mysqld as root. 2. ...‘), (‘MySQL vs. YourSQL‘,‘In the following database comparison ...‘), (‘MySQL Security‘,‘When configured properly, MySQL ...‘);
- 使用全文索引误区(like查询):
不会使用索引:
select * from articles where body like ‘%mysql%’;
正确使用索引:
select * from articles where match(title,body) against(‘database’);
- 全文索引使用说明:
- 在mysql中fulltext 索引只针对 myisam生效。
- mysql自己提供的fulltext针对英文生效。处理中文需要使用sphinx (coreseek) 技术。
- 使用方法是 match(字段名..) against(‘关键字’)。
- 全文索引"停止词"意义": 因为在一个文本中,创建索引是一个无穷大的数,因此,对一些常用词和字符,就不会创建,这些词,称为停止词。
- 创建唯一索引
当表的某列被指定为unique约束时,这列就是一个唯一索引。
unique字段可以为NULL,并可以有多NULL, 但是如果是具体内容,则不能重复。创建表后再添加唯一索引:
create unique index 索引名 on 表名 (列名..);
查询
- desc 表名 【该方法的缺点是: 不能够显示索引名.】
- show index(es) from 表名
- show keys from 表名
删除
alter table 表名 drop index 索引名;
修改
先删除,再重新创建
索引使用的注意事项
- 创建索引会占用磁盘空间。
- 创建索引后,会降低dml操作速度。
- 创建索引的建议:
- 肯定在where条件中经常使用的列
- 该字段的值不是固定的一个或几个值。变化范围(散列度)要大,唯一性要好。
比如订单表的状态(成功、失败、处理中),这种字段就不适合创建索引。
Mysql索引生效规则
- 为多个列创建独立索引,在where条件中使用多个列作为查询条件,只能使用到一个索引。
实例1:
where a = 1 and b = 2;(a、b都加上索引)
该查询只能用上a或b的索引。因为独立索引只会同时使用一个。 - mysql多列索引生败规则
实例2:
假设某个表有一个联合索引(c1,c2,c3,c4),以下哪些项目只能使用该联合索引的c1,c2,c3部分
A where c1=x and c2=x and c4>x and c3=x
B where c1=x and c2=x and c4=x order by c3
C where c1=x and c4= x group by c3,c2
D where c1=? and c5=? order by c2,c3
E where c1=? and c2=? and c5=? order by c2,c3A:使用了c1,c2,c3,c4索引。
B:使用了c1,c2,c3索引。c1,c2索引用于查询,c3索引用于排序。
C:只使用c1索引。
D:使用了c1,c2,c3索引。c1索引用于查询,c2,c3索引用于排序。
D:使用了c1,c2,c3索引。c1,c2索引用于查询,c3索引用于排序。
因此对于联合索引,必须要满足左前缀匹配规则:
1. 索引列从左到右的使用在where条件中。
2. 前一个索引列使用了范围查询,后面的索引列将不会使用索引。
3. 索引列使用了通配符查询‘%xx%‘,‘%aaa‘不会使用索引,使用‘xx%‘形式的通配符查询,可以正常使用索引。
Mysql索引长度选择
对要创建索引的列,使用如下方式计算索引的区分度。一般比例在1:10之内都可以接受。
select count(distinct left(column_name,length))/ count(*)from table;
通过不断的增大length值来决定此列创建的索引长度再那个值比较整理。既能达到索引的效果又能减小索引文件大小。
创建索引时指定长度:
alter table table_name add index index_name(column_name(length));
使用伪哈希函数降低索引长度
比如网站
等类似列,前面一部分都是固定格式,如果创建索引,前面一部分都一样,因此就会浪费一段空间。
这种情况可以采用下面两种方案创建索引降低索引长度。
一、使用字符函数将内容顺序反转再创建索引。这样就可以设置索引长度,避免将后面相同部分也创建在索引中而增加索引长度。
二、创建表时额外多创建一个字段,该字段为unsigned Int型,储存数据时,使用crc32()函数为值计算一个int值存储在额外字段中。然后在额外字段上创建索引,由于int 固定占4个字节,这样就大大降低索引长度。查询是须记住先将值使用crc32(value)计算后再查询。
使alter 修改表属性
修改表名:
alter table t_name rename to new_name;
添加列:
alter table t_name add column type;
列重命名:
alter table t_name change column old_name new_name type;
同时修改列和类型:
alter table t_name change column old_name new_name type;
更改列类型:
alter table t_name modify column col_name type;
modify与chage区别:
Modify 只修改列的类型
删除列:
alter table t_name drop column col_name;
内置函数
right(column,number)
从列的右边取指定数量的字符
left(column,number)
从列的左边取出指定数量的字符
substring_index(column,parten,number)
截取列中第number次出现parten位置之前的所有内容
select * from t2;
+-------+-------+------------+--------+
| col_1 | col_2 | col_3 | col_4 |
+-------+-------+------------+--------+
| 1 | a | a,b,c,d,e, | abcdef |
+-------+-------+------------+--------+
select substring_index(col_3,‘,‘,2) from t2;
+------------------------------+
| substring_index(col_3,‘,‘,2) |
+------------------------------+
| a,b |
+------------------------------+
substring(column,start_position,length)
从列的start_position位置取出length个长度字符
upper(your_string) 和 lower(your_string)将字符串转换为大写或小写
reverse(your_string) 反转字符串里的字符排序
ltrim(your_string) 和 rtrim(your_string) 返回清除多余空格后的字符串,它们分别清除字符左端(前端) 和右侧(后面)的多余空格
length(your_string)返回字符串的字符数量