★SQL语句优化的一般步骤
通过show status命令了解SQL语句的执行频率(重点是增删改查)
show [session|global] status;
session:(默认)表示当前的连接
global:表示自数据库启动至今
也可使用like语句 show status like "Com_%";
【参数说明】
[Com_XXX] Com_select 执行select操作的次数,一次查询只累计1,与影响行数无关
Com_update 执行update操作的次数
Com_insert 执行insert操作的次数,对于批量插入算为1次
Com_delete 执行delete操作的次数
[InnoDB] InnoDB_rows_read 执行select操作的次数
InnoDB_rows_updated 执行update操作的次数
InnoDB_rows_insert 执行insert操作的次数
InnoDB_rows_delete 执行delete操作的次数
注:InnoDB考虑的是影响的行数
通过alter table t2 engine=innodb;可以切换成innodb表引擎
【其他参数】
connections 连接mysql的数量(无论登录是否成功,都会被记录下来)
uptime 服务器已经工作的秒数
slow_queries 慢查询的次数
定位执行效率较低的SQL语句
通过慢查询日志来查(记录了超过10s的语句,表明很有可能存在问题)
explain select * from table where id=100;
desc select * from t1\G
[显示条目] id:1
select_type:SIMPLE 表示select的类型,常见取值有
SIMPLE 简单查询,没有用到多表查询或者子查询
PRIMARY 主查询,即外层的查询
UNION 第二个或后面的查询语句
SUBQUERY 子查询中的第一个select
table:t1 输出结果集的表
type:range 表示表的连接类型,性能由好到差依次为
system 表仅一行、const 只一行匹配
eq_ref 对于前面的每一行使用主键和唯一
ref(同eq_ref,但没有使用主键和唯一)
ref_or_null 同前面对null查询
index_merge 索引合并优化、unique_subquery主键子查询
index_subquery 非主键子查询、range 表单中的查询范围
index 都通过查询索引来得到数据、all 通过全表扫描得到数据
possible_keys:name 表查询时可能使用到的索引
key:name 表示实际使用的索引
key_len:50 索引字段的长度
ref:NULL
rows:8 扫面行的数量 <==重点查看的内容
Extra:Using where;Using index 执行情况的说明和描述
重点看影响行数,是多表查询还是单表查询,有没有用到索引,索引用到字段的最大长度
【总结】一般步骤为:
通过慢查询日志查看SQL语句
通过SQL语句查看其影响行数
影响行数特别多的话要进而判断是否需要加索引
★索引优化
索引是数据库优化中最常见也是最重要的手段,通过索引通常可以帮助用户解决大多数的SQL性能问题
索引用于快速找出在某个列中有一特定值的行,对相关列使用索引是提高select操作性能的最佳途径
MyISAM存储引擎的表的数据和索引是自动分开存储的,各自是独立的一个文件
InnoDB存储引擎的表的数据和索引是存储在同一个表空间里面的,但可以由多个文件组成
MySQL目前不支持函数索引,但是可以针对列的前面某一部分进行索引,例如name字段,可以只取name的前4个字符进行索引,这个特性可以大大缩小索引文件的大小,因此在设计表结构的时候也可以根据此特性对文本列进行灵活设计
create index ind_com_name on com(name(4));
使用索引的情形:
对于创建的多列索引,只要查询条件中用到最左面的列,索引一般就会被使用
create index ind_sa on sa(com,mon); 创建复合索引
explain select * from sa where com=2006\G 使用了索引
explain select * from sa where mon=100\G 没有使用索引
使用like的查询,后面如果是常量并且%不在第一个字符,索引才会被使用
explain select * from com where name like "%2"\G;
百分号在后面可能会用到索引,而百分号在前面可能索引会失效
如果对大的文本进行搜索一般用全文匹配查找而不用like
如果是列名索引,搜索 col is null时会用到索引
存在索引但不使用的情形:
如果mysql估计使用索引比全表扫描更慢,则不使用索引
例如:id列均匀分布在1-100之间,查询时使用索引就不是很好
如果使用MEMORY/HELP表并且where条件中不使用"="进行索引列,那么不会使用索引
用or分隔开的条件,如果or前的条件中的列有索引,而后面的列没有索引,那么涉及到的索引都不会被使用
使用and或者or只有前后列都有索引,涉及到的索引才会被引用
如果列是字符串类型(name)
但查询条件为name=2000,这时候不会用到索引
但是name="2000" 会用到索引
查看索引的使用情况:
如果索引正在工作,Handler_read_key的值会很高,这个值代表了一个行被索引值读的次数
Handler_read_md_next的值高则意味着查询运行低效,并且应该建立索引补救
show status like "Handler_read%"
其他:
嵌套查询内查询使用索引,外查询不使用索引
左连接两个表都使用索引
所以要避免使用嵌套查询,尽可能去使用连接和多表查询
★表优化
检测一个或多个表是否有错误
check table table_name;
定期优化表
optimize table sales;
如果已经删除了表的一大部分,或者如果已经对含有可变长度行的表进行了很多次改动,则需要做定期优化。这条命令可以将表中的空间碎片进行合并,但是此命令只对MySIAM、BDB、和InnoDB表起作用
★常用的SQL优化
大量插入数据
当用load命令导入数据的时候,适当设置可以提高导入速度
[针对MyISAM引擎的表]
alter table table_name disable keys 关闭MyISAM表非唯一索引的更新
loading the data 加载数据
alter table table_name enable keys 打开MyISAM表非唯一索引的更新
注意:对InnoDB表无效
infile、onfile
select * from t1 into outfile "/tmp/test.txt"; 只保留内容,不保留表结构
load data infile "/tmp/test.txt" into table t1;
唯一性校验
关闭唯一性校验:set unique_checks=0
恢复唯一性校验:set unique_checks=1
针对InnoDB表的优化
关闭自动提交可以提高导入效率 set autocommit=0 关闭自动提交
导入数据
set autocommit=1 恢复自动提交
因为InnoDB表是按照主键顺序来保存的,所以将导入的数据按照主键顺序排列,可以有效的提高导入数据的效率
优化insert
尽量使用同时插入多个数据的insert语句,可以大大减少客户与数据库频繁连接关闭造成的损耗
如:insert into t1 values("user1"),("user2"),("user3");
可以使用insert delayed(马上执行)语句得到更高的效率
将索引文件和数据文件分别存放在不同的磁盘上
可以增加bull_insert_buffer_size变量值方法来提高速度(针对MyISAM表)
优化group by
如果查询包含group by 但用户想要避免排序结果的损耗,则可以使用order by null来禁止排序
★数据库优化
外键 优化表的类型 通过拆分提高表的访问效率
使用中间表:表或视图(相比之下视图更合适,视图数据的同步更新要比表快)
★mysql服务器优化
myisam读锁定、myisam写锁定
lock table t1 read
这时候使用另一个用户去对t1表进行增删改操作会发现所有的数据都只停留在终端上而没有真正去操作
读锁定是自己可以读别人也可以读,但是谁也不能进行增删改,解除锁定后才可进行相关操作
读锁定在对大量数据进行备份时非常有用(-L 添加读锁)
unlock tables; 解除锁定
写锁定:只有本人可以写,别人增删改查都做不了
bin-log日志
show variables like "%bin%"; 查看是否开启了bin-log日志
log-bin=mysql-bin (/etc/my.cnf下)
慢查询日志、慢查询时间
show variables like "%slow"; 查看是否开启了慢查询日志
vim /etc/my.cnf
[mysqld]
log_slow_queries=slow.log 开启慢查询日志
long_query_time=5 大于2s被记载