3.1 SQL语句的一般优化步骤
session :(默认的)表示当前连接
global: 表示自数据库启动至今.
-1. show status ; //用于了解SQL语句的执行频率,重点跟踪以com开头的命令.
-2. show status like "com_insert %" //显示执行插入语句的次数.(批量操作只算 1 条执行语句).
-3. show status like "com_select%" //显示执行查询语句的次数.
-4 show status like "com_update%" //显示执行更新语句的次数
-5 show status like "com_delete%" //显示执行删除语句的次数.
只针对inndb存储引擎的
-1. show status like "innodb_rows_read"; //显示执行查询语句的次数.
-2. show status like "innodb_rows_inserted"; //显示执行插入语句的次数.
-3. show status like "innodb_rows_updated" //显示执行更新语句的次数.
-4. show status like "innodb_rows_deleted" //显示执行删除语句的次数.
-5. show status like "%connections%"; //显示 MySQL的数量;
-6. show status like "%uptime%" //显示服务器工作的时间(以秒为单位)
-7. show status like "%slow_queries%" //显示慢查询的次数.
-8. show variable like "%quer%"; //显示慢查询是否被开启.
-8: //显示: log_slow_queries off //慢查询日志没有开启
-9. show variable like "%connection%" //显示MySQL服务器的连接数.
-9. //显示: max_connections 100 //最大连接数
10. show status like"%conn%"; //显示MySQL服务器的连接数.
10. //显示: Connection 3 //试图连接到(不管是否成功)MySQL服务器的连接数
10. //显示: Max_used_connections 3 //服务器启动后已经同时使用的连接的最大数量
10. //显示: Threads_connected 3 //当前的连接数
开启慢查询日志: ( 这里有讲开启慢查询日志 )
-1. Linux下
找到mysql的配置文件my.ini, 在mysqld下方加入慢查询的配置语句(注意:一定要在[mysqld]下的下方加入)
log-slow-queries = /var/lib/mysql/mysql-slow.log
long_query_time = 10
-2. Windows下
log-slow-queries = C:/Program Files/MySQL/MySQL Server 5.5/log/mysql-slow.log" // windows下一定要写绝对路径.
long_query_time = 10 // 最长执行时间,可根据实际情况更改.
慢查询:默认是关闭的. 开启慢查询后,一条语句执行时间超过10秒就会被记录.
3.1.2 定位执行效率低的语句的步骤;
-1. 查慢查询日志.
-2. 查异常语句影响行数.
-3. 检查是否使用索引或者索引是否被执行.
-4. desc ... 语句执行后检查是否优化.(主要是围绕索引优化)
desc select * from t1 where id=1 \G // 注意不加 ; 号
mysql> desc select * from t1 where id=1 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra:
1 row in set (0.00 sec)
-1. rows 1 // 影响行数,扫描行的数量
-2. select_type SIMPLE // simple 表示不使用表连接或子查询, primary 主查询(外层查询), union(union中的第二个查询),
subqurty子查询的第一个select.
-3. table t1 // 输出结果集的表
-4. possible_keys: PRIMARY // 可能用到的suoyin
-5. key: PRIMARY // 实际使用的索引
-6. type: const // 表的连接类型, system (表仅一行), const(只一行匹配), eq_ref(对于前面的每一行使用主键和唯一索引)
ref(没有使用主键和唯一索引), range(范围查询), index_merge(索引合并优化),
unique_subquery(主键子查询), index_subquery(非主键子查询)
index(通过查询索引得到数据), all(通过全表扫描得到数据.应该避免全表扫描.)
// 注意: 一般问题多在order by .. group by.. Where.. 等条件语句后没有加索引或索引失效引起的查询慢.
-7. ref: // 推荐使用的索引类型
-8. Extra:Using where; Using index // 使用过where , 使用过索引
3.2 索引问题
3.2.1 索引的存储分类
-1. myisam存储引擎的表的数据和索引是自动分来存储的,各自是独立的一个文件.
-2. innodb存储引擎的表的数据和索引是存储在同一个表的空间里面,但是可以有多个文件组成.
-3. MySQL暂时不支持函数索引.
// 注意: 索引一般加在条件语句后如where... having... group by... order by... 或者频繁使用的语句.
3.2.2 使用索引
-1 如何使用索引
-1.1. 对于创建的多列索引,只要查询的条件中用到最左边的列,索引一般就会被使用.
show index from t1 //查询t1表的索引
drop index inx_name on t1; //删除t1表的名为inx_name的索引.
select * from t1 where name="user0"; //查询name是user0的列
create index inx_sum on t1(name,salary); //给name列和salary列添加联合索引
desc select * from t1 where name="user0") \G //显示 索引被使用, rows只查了1行. 所以只要查询的条件中用到最左边的列,索引一般就会被使用.
desc select * from t1 where salary=101 \G //显示没有使用索引.rows查询了10行. 查询联合索引的右侧的列,索引没有被使用.
-1.2. 使用 like 查询 如果%不是第一个字符,可以使用索引,否则索引失效.
drop index inx_sum on t1 ; //删除t1表的名字是inx_sum的索引
create index inx_name on t1(name) ; //给t1表name列创建名为inx_name的索引.
desc select * from t1 where name like "%ser%" \G //显示 rows查询了所有列. 索引失效.
desc select * from t1 where name like "user5%" \G //显示 rows查询了2行,索引可以用.
-1.3. 列名是索引,使用column_name is null 将使用索引.
-2 存在索引,但不使用索引的情况
-2.1. 如果SQL计算使用索引比全表扫描时间长,将放弃使用索引.
-2.2. 用or分割开的语句,如果or左侧使用索引,右侧没有使用索引,那么将都不使用索引.
-2.3. 如果表使用了联合索引(2个列一起被创建为索引) 只有 create index inx_sum on t1(name,salary); 的name列可以使用索引.salary列将不使用索引.
-2.4 like 是以%开头的,将不使用索引. 如 select * from t1 where name like" user5%" \G //将使用索引.
-2.5 如果列类型是字符串,查询时候使用了 int型.也将不会使用索引
desc select * from t2 where name = 1 \G //将不会使用索引
show atatus like "handler_read%";
// 显示: handler_read_key值很高,说明索引实用正常.
// 显示: handler_read_rnd_next 值涵高, 就说明需要检查索引是否存在或者有效.
3.3 实用的表优化
3.3.1 定期分析表和检查表
analyze table sales; //用于分析和存储表的关键字分布,
check table table_name // 用于检查表是否正常可用.
3.3.3 定期表优化
如果有频繁删除表或者修改表字段长度.需要定期做优化.合并空间碎片.
optimize table table_name //优化表空间,提取碎片和空洞. 注意只针对myisam, bdb, innodb表引擎有效.
3.4 常用SQL优化
3.4.1 大批量导入导出数据
myisam引擎使用load命令时候可以配合使用:
alter table t1 disable keys; //关闭使用t1表的索引. 在myisam引擎下会提高导出速度.
alter table t1 enable keys; //恢复使用t1表的索引.
注意: 唯一索引不建议关闭.
-1. innodb引擎表的主键是顺序保存的,将导出数据的主键,顺序排列用可以提高导入数据的效率. (linux下的命令语句)
load data infile"/test.txt" into t1(name); //给t1表的name列快速导入数据.
select name from t1 into outfile"/test.txt"; //导出t1表的name列数据快速导出到test.txt文件中.(适合新手,大神,请收下膝盖)
-2. 关闭唯一性校检可以提高效率.
在导入数据前先执行 set unique_checks=0; //关闭唯一性校检. 导入数据结束后在恢复唯一性校检. set unique_checks=1;
--- 如果确定关闭唯一索引不会引起问题, 关闭唯一索引在导入数据也会提高效率.
-3. 关闭自动提交可以提高导入速度.
在导入数据前先关闭自动提交,也可以提高导入速度. set autcommit=0; //关闭自动提交事务. set autocomit=1; //打开自动提交.
3.4.2 优化insert 语句
insert into t1(name) values ("user1"), ("user2"), ("user3"); //一次插入多值,减少表连接次数.也可以提高效率.
3.4.3 优化group by 语句
分组语句默认带升序排序.可以使用 order by null 来禁止其排序来提高效率.
select * from t1 where group by name order by null;
3.4.5 优化嵌套排序
嵌套查询效率没有表连接效率高. 建议使用表连接来代替嵌套查询.
当使用嵌套查询时: 如果内外侧查询都使用了索引, 就只有内侧查询索引有效. 外层查询索引没用.
select * from t1 where id in(select id from t2); //外层select查询索引没有用.只有内层查询索引有效.
等价于
select t1.* from t1, t2 where t1.id = t2.id; // 表连接不会有索引失效问题 (如果索引创建正确的话)