SQL优化
1.查看各种SQL执行的频率
mysql> show status like ‘Com_select‘;--Com_insert,Com_delete,connections(试图连接mysql服务的次数),uptime(mysql工作时间),slow_queries(慢查询次数)等等
2.定位执行效率较低的SQL语句
通过慢查询日志,定位查询效率低下的SQL语句,然后分析语句进行优化
3.通过explain或desc分析SQL语句的执行计划,如要查看所访问的分区使用explain partitions
mysql> desc select email from users\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: users type: index //扫描方式,效率由低到最好 all(全表)->index(索引全扫描)->range(索引范围扫描)->ref(非唯一索引)->eq_ref(唯一索引)->const/system->null possible_keys: NULL key: email key_len: 153 ref: NULL rows: 59 Extra: Using index 1 row in set (0.00 sec)
4.使用profile分析SQL,profile就是详细地列出SQL语句执行过程
查看是否开启/支持profile
mysql> show variables like ‘profiling‘; --使用select @@have_profiling也可以 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | profiling | OFF | +---------------+-------+ mysql> set profiling=on --开启 OFF--关闭
查看所有查询分别执行的时间
mysql> show profiles; +----------+------------+---------------------------------+ | Query_ID | Duration | Query | +----------+------------+---------------------------------+ | 1 | 0.00079925 | show variables like ‘profiling‘ | | 2 | 0.00050700 | select * from users | | 3 | 0.36104925 | select * from tb_5 | +----------+------------+---------------------------------+
查看某个查询语句执行过程每个状态以及消耗的时间
mysql> show profile for query 3; +----------------------+----------+ | Status | Duration | +----------------------+----------+ | starting | 0.000059 | | checking permissions | 0.000010 | | Opening tables | 0.042742 | | System lock | 0.000018 | | init | 0.000017 | | optimizing | 0.000004 | | statistics | 0.000162 | | preparing | 0.000010 | | executing | 0.000003 | | Sending data | 0.317929 | --主要时间花费在将数据发送到客户端 | end | 0.000011 | | query end | 0.000007 | | closing tables | 0.000013 | | freeing items | 0.000058 | | logging slow query | 0.000005 | | cleaning up | 0.000004 | +----------------------+----------+
5. 使用optimizer_trace分析优化器查看SQL语句执行计划(5.6版本以上)
mysql> show variables like ‘optimizer_trace‘; +-----------------+--------------------------+ | Variable_name | Value | +-----------------+--------------------------+ | optimizer_trace | enabled=off,one_line=off | +-----------------+--------------------------+
开启trace分析器,并调整最大可用内存
mysql> set optimizer_trace=‘enabled=on‘,end_markers_in_json=on; --以JSON格式显示 Query OK, 0 rows affected (0.05 sec) mysql> set optimizer_trace_max_mem_size=1000000; Query OK, 0 rows affected (0.16 sec)
通过information_schema库的optimizer_trace视图查看trace信息
mysql> select query,trace from optimizer_trace\G *************************** 1. row *************************** query: select * from test.stu trace: { "steps": [ { "join_preparation": { "select#": 1, "steps": [ { "expanded_query": "/* select#1 */ select `test`.`stu`.`sno` AS `sno`,`test`.`stu`.`sname` AS `sname`,`test`.`stu`.`sclass` AS `sclass` from `test`.`stu`"-------------------只截取了部分信息,通过分析这些信息可用对SQL语句进行相应优化---------------------
6.使用索引优化查询性能
索引是数据库优化中最常用的最要种的手段,索引可以分为以下4中:
HASH索引:只有MEMORY引擎支持; B-TREE索引:平衡树索引,最常用的索引 R-TREE索引:MyISAM引擎特殊索引 FULL-TREE全文索引:MyISAM特殊索引。
创建索引:
mysql> create index idx_name on stu(sname); Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0
查看某表的所有索引
mysql> show index from stu\G *************************** 2. row *************************** Table: stu Non_unique: 1 Key_name: idx_name Seq_in_index: 1 Column_name: sname Collation: A Cardinality: 4 Sub_part: NULL Packed: NULL Null: YES Index_type: BTREE
MySQL能够使用索引的一些情况:匹配索引全值,匹配值的范围查询,匹配最左前缀等等。
查看索引使用情况,如果handle_read_key值很高,说明查询效率很高,如Handler_read_rnd_next值很高,说明查询效率并不理想。
mysql> show status like ‘Handler_read%‘; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | Handler_read_first | 1 | | Handler_read_key | 1 | | Handler_read_last | 0 | | Handler_read_next | 0 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 25 | +-----------------------+-------+
7.定期检查表和分析表,以及优化表
检查表就是检查一个或多个表是否有错误
mysql> check table stu; +--------+-------+----------+----------+ | Table | Op | Msg_type | Msg_text | +--------+-------+----------+----------+ | zz.stu | check | status | OK | +--------+-------+----------+----------+
分析表主要作用是让SQL生成正确的执行计划
mysql> analyze table stu; +--------+---------+----------+----------+ | Table | Op | Msg_type | Msg_text | +--------+---------+----------+----------+ | zz.stu | analyze | status | OK | +--------+---------+----------+----------+
优化表的作用主要是对表空间的碎片进行合并以及回收删除或更新造成浪费的空间
mysql> optimize table t1; --对于InnoDB的表,会有Table does not support optimize, doing recreate + analyze instead提示,可以在启动mysql服务时,指定--skip-new或--safe-mode即可 +---------+----------+----------+----------+ | Table | Op | Msg_type | Msg_text | +---------+----------+----------+----------+ | test.t1 | optimize | status | OK | +---------+----------+----------+----------+ 1 row in set (0.04 sec)
8.常用SQL优化
加载大量数据时,关闭非唯一索引,取消唯一性检查,以及取消自动提交以提高插入速度
set unique_checks=0 alter table stu disable keys set autocommit=0 load load infile........ alter table stu enable keys set unique_checks=1 set autocommit =1
insert语句优化,一次性插入多条记录
mysql> insert into stu values (4010409,‘钟小兆‘,‘A1114‘,22,0),(4010408,‘肖小杰‘,‘A1114‘,21,1).....;
order by语句排序优化,优化思路就是尽可能的减少额外的排序(filesort),通过索引直接返回有序数据,例如
mysql> explain select sno from stu order by sname desc; +----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ | 1 | SIMPLE | stu | index | NULL | idx_name | 93 | NULL | 6 | Using index | +----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+
where条件和order by 字段使用相同的索引,并且order by的顺序和索引顺序相同,还有order by的字段都是降序或者升序。例如:
以下情况会使用索引,前提(key-part1,key_part2)为联合索引
select * from tbl_name order by key_part1,key_part2....; select * from tbl_name where key_part1=xxx order by key_part1,key_part2....; select * from tbl_name order by key_part1 asc,key_part2 asc....;
以下情况则不会使用索引,(key1,key2分别建立索引)
select * from tbl_name order by key1,key2....; select * from tbl_name where key1=xxx order by key2; select * from tbl_name order by key_part1 asc,key_part2 desc....;
SELECT查询时最好指定具体的字段名,SELECT * 会选择所有字段,会增加排序区的使用,降低SQL性能
group by语句优化
MySQL默认情况下对group by col1,col2..的字段进行排序,可以通过指定order by null来消除这种排序
or条件优化
用到OR的查询,如果要使用索引,那OR之间的每个条件必须是索引,并且要分别建立索引,不能使用联合索引。