sql 语句优化
1. sql优化的一般步骤
2. 定位问题sql
2.1 查看当前线程
MysqL> show processlist\G
*************************** @H_502_105@. row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: starting
Info: show processlist
*************************** @H_502_105@. row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: starting
Info: select * from customer where balance=@H_502_105@;
rows in set @H_502_105@( sec@H_502_105@)
有时 sql 语句比较复杂,而且执行量较大,通过 show processlist 来查看不太方便,这时可以通过表@R_992_4045@ion_schema.processlist 进行查看,还可以自定义查询方式。
MysqL> select * from @R_992_4045@ion_schema@H_502_105@.processlist order by info desc\G
*************************** @H_502_105@. row ***************************
ID:
USER: root
HOST: localhost
DB: tempdb
COMMAND: Query
TIME:
STATE: executing
INFO: select * from @R_992_4045@ion_schema@H_502_105@.processlist order by info desc
*************************** @H_502_105@. row ***************************
ID:
USER: root
HOST: localhost
DB: tempdb
COMMAND: Sleep
TIME:
STATE:
INFO: NULL
rows in set @H_502_105@( sec@H_502_105@)
2.2 慢日志
3. 分析 sql 执行计划
找到问题 sql 后,通过 explain 命令查看执行计划:
MysqL> explain select * from customer where balance=\G
*************************** @H_502_105@. row ***************************
id:
select_type: SIMPLE
table: customer
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows:
Extra: Using where
row in set@H_502_105@, warning @H_502_105@( sec@H_502_105@)
其中 select_type 表示 select 类型,一般值为 simple、primary、union、subquery。type 表示访问类型,常见值有(性能由差到好):ALL、index、range、ref、eq_ref、const:
- type 等于 ALL,表示全表扫描,需要遍历全表所有的数据;
- type 等于 index,表示索引全扫描,需要遍历整个索引来查找需要的数据;
- type 等于 range,表示索引范围扫描,扫描索引部分数据即可查找需要的数据,常见操作有大于、小于、between;
- type 等于 ref,使用唯一或非唯一索引的前缀扫描,返回查找到的单独值;
- type 等于 eq_ref,使用唯一索引,且仅有一条记录匹配;
- type 等于 const,表中仅有一行数据是匹配的。
4. 分析 sql Profile
想要进一步分析 sql,可以通过 show profiles 命令:
MysqL> select * from customer where balance=@H_502_105@;
MysqL> show profiles@H_502_105@;
+----------+------------+-----------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------------+
| | | select @@profiling |
| | | SELECT DATABASE@H_502_105@(@H_502_105@) |
| | | select * from customer where balance= |
+----------+------------+-----------------------------------------+
rows in set@H_502_105@, warning @H_502_105@( sec@H_502_105@)
MysqL> show profile for query @H_502_105@;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | |
| checking permissions | |
| opening tables | |
| init | |
| System lock | |
| optimizing | |
| statistics | |
| preparing | |
| executing | |
| Sending data | |
| end | |
| query end | |
| closing tables | |
| freeing items | |
| cleaning up | |
+----------------------+----------+
rows in set@H_502_105@, warning @H_502_105@( sec@H_502_105@)
5. 实施优化措施
MysqL> alter table customer add index idx_balance@H_502_105@(balance@H_502_105@)@H_502_105@;
Query OK@H_502_105@, rows affected @H_502_105@( sec@H_502_105@)
Records: Duplicates: Warnings:
MysqL> explain select * from customer where balance=\G
*************************** @H_502_105@. row ***************************
id:
select_type: SIMPLE
table: customer
partitions: NULL
type: ref
possible_keys: idx_balance
key: idx_balance
key_len:
ref: const
rows:
Extra: NULL
row in set@H_502_105@, warning @H_502_105@( sec@H_502_105@)
从执行计划,可以看出,扫描行数从20965行减少至10行,查找效率可以大大提升。