《MysqL应用SQL语句优化的一般步骤详解》要点:
本文介绍了MysqL应用SQL语句优化的一般步骤详解,希望对您有用。如果有疑问,可以联系我们。
MysqL实例前言
MysqL实例本文主要给大家分享了关于SQL语句优化的一般步骤,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧.
MysqL实例一、通过 show status 命令了解各种 sql 的执行频率
MysqL实例MysqL 客户端连接成功后,通过 show [session|global] status
命令可以提供服务器状态信息,也可以在 *** 作系统上使用 MysqLadmin extend-status
命令获取这些消息.
MysqL实例show status
命令中间可以加入选项 session(默认) 或 global:
MysqL实例# Com_xxx 表示每个 xxx 语句执行的次数.MysqL> show status like 'Com_%';
MysqL实例我们通常比较关心的是以下几个统计参数:
Com_select : 执行 select *** 作的次数,一次查询只累加 1. Com_insert : 执行 insert *** 作的次数,对于批量插入的 insert *** 作,只累加一次. Com_update : 执行 update *** 作的次数. Com_delete : 执行 delete *** 作的次数.MysqL实例上面这些参数对于所有存储引擎的表 *** 作都会进行累计.下面这几个参数只是针对 innodb 的,累加的算法也略有不同:
Innodb_rows_read : select 查询返回的行数. Innodb_rows_inserted : 执行 insert *** 作插入的行数. Innodb_rows_updated : 执行 update *** 作更新的行数. Innodb_rows_deleted : 执行 delete *** 作删除的行数.MysqL实例通过以上几个参数,可以很容易地了解当前数据库的应用是以插入更新为主还是以查询 *** 作为主,以及各种类型的 sql 大致的执行比例是多少.对于更新 *** 作的计数,是对执行次数的计数,不论提交还是回滚都会进行累加.
MysqL实例对于事务型的应用,通过 Com_commit
和 Com_rollback
可以了解事务提交和回滚的情况,对于回滚 *** 作非常频繁的数据库,可能意味着应用编写存在问题.
MysqL实例此外,以下几个参数便于用户了解数据库的基本情况:
Connections : 试图连接 MysqL 服务器的次数. Uptime : 服务器工作时间. Slow_querIEs : 慢查询次数.MysqL实例二、定义执行效率较低的 sql 语句
MysqL实例1. 通过慢查询日志定位那些执行效率较低的 sql 语句,用 --log-slow-querIEs[=file_name]
选项启动时,MysqLd 写一个包含所有执行时间超过 long_query_time 秒的 sql 语句的日志文件.
MysqL实例2. 慢查询日志在查询结束以后才记录,所以在应用反映执行效率出现问题的时候慢查询日志并不能定位问题,可以使用 show processList 命令查看当前 MysqL 在进行的线程,包括线程的状态、是否锁表等,可以实时的查看 sql 的执行情况,同时对一些锁表 *** 作进行优化.
MysqL实例三、通过 explain 分析低效 sql 的执行计划
MysqL实例测试数据库地址:https://downloads.MysqL.com/docs/sakila-db.zip(本地下载)
MysqL实例统计某个 email 为租赁电影拷贝所支付的总金额,需要关联客户表 customer 和 付款表 payment,并且对付款金额 amount 字段做求和(sum) *** 作,相应的执行计划如下:
MysqL实例MysqL> explain select sum(amount) from customer a,payment b where a.customer_ID= b.customer_ID and a.email='JANE.BENNETT@sakilacustomer.org'\G *************************** 1. row *************************** ID: 1 select_type: SIMPLE table: a partitions: NulL type: ALLpossible_keys: PRIMARY key: NulL key_len: NulL ref: NulL rows: 599 filtered: 10.00 Extra: Using where*************************** 2. row *************************** ID: 1 select_type: SIMPLE table: b partitions: NulL type: refpossible_keys: IDx_fk_customer_ID key: IDx_fk_customer_ID key_len: 2 ref: sakila.a.customer_ID rows: 26 filtered: 100.00 Extra: NulL2 rows in set,1 warning (0.00 sec)
select_type: 表示 select 类型,常见的取值有:simple:简单表,及不使用表连接或者子查询
primary:主查询,即外层的查询
union:union 中的第二个或后面的查询语句
subquery: 子查询中的第一个 select table : 输出结果集的表 type : 表示 MysqL 在表中找到所需行的方式,或者叫访问类型,常见类型性能由差到最好依次是:all、index、range、ref、eq_ref、const,system、null:
MysqL实例1.type=ALL
,全表扫描,MysqL 遍历全表来找到匹配的行:
MysqL实例MysqL> explain select * from film where rating > 9 \G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: film partitions: NulL type: ALLpossible_keys: NulL key: NulL key_len: NulL ref: NulL rows: 1000 filtered: 33.33 Extra: Using where1 row in set,1 warning (0.01 sec)
MysqL实例2.type=index
,索引全扫描,MysqL 遍历整个索引来查询匹配的行
MysqL实例MysqL> explain select Title form film\G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: film partitions: NulL type: indexpossible_keys: NulL key: IDx_Title key_len: 767 ref: NulL rows: 1000 filtered: 100.00 Extra: Using index1 row in set,1 warning (0.00 sec)
MysqL实例3.type=range
,索引范围扫描,常见于<、<=、>、>=、between等 *** 作:
MysqL实例MysqL> explain select * from payment where customer_ID >= 300 and customer_ID <= 350 \G *************************** 1. row *************************** ID: 1 select_type: SIMPLE table: payment partitions: NulL type: rangepossible_keys: IDx_fk_customer_ID key: IDx_fk_customer_ID key_len: 2 ref: NulL rows: 1350 filtered: 100.00 Extra: Using index condition1 row in set,1 warning (0.07 sec)
MysqL实例4.type=ref
,使用非唯一索引扫描或唯一索引的前缀扫描,返回匹配某个单独值的记录行,例如:
MysqL实例MysqL> explain select * from payment where customer_ID = 350 \G *************************** 1. row *************************** ID: 1 select_type: SIMPLE table: payment partitions: NulL type: refpossible_keys: IDx_fk_customer_ID key: IDx_fk_customer_ID key_len: 2 ref: const rows: 23 filtered: 100.00 Extra: NulL1 row in set,1 warning (0.01 sec)
MysqL实例索引 IDx_fk_customer_ID
是非唯一索引,查询条件为等值查询条件 customer_ID = 350
,所以扫描索引的类型为 ref.ref 还经常出现在 join *** 作中:
MysqL实例MysqL> explain select b.*,a.* from payment a,customer b where a.customer_ID = b.customer_ID \G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: b partitions: NulL type: ALLpossible_keys: PRIMARY key: NulL key_len: NulL ref: NulL rows: 599 filtered: 100.00 Extra: NulL*************************** 2. row *************************** ID: 1 select_type: SIMPLE table: a partitions: NulL type: refpossible_keys: IDx_fk_customer_ID key: IDx_fk_customer_ID key_len: 2 ref: sakila.b.customer_ID rows: 26 filtered: 100.00 Extra: NulL2 rows in set,1 warning (0.00 sec)
MysqL实例5.type=eq_ref
,类似 ref,区别就在使用的索引时唯一索引,对于每个索引的键值,表中只要一条记录匹配;简单的说,就是多表连接中使用 primary key
或者 unique index
作为关联条件.
MysqL实例MysqL> explain select * from film a,film_text b where a.film_ID = b.film_ID \G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: b partitions: NulL type: ALLpossible_keys: PRIMARY key: NulL key_len: NulL ref: NulL rows: 1000 filtered: 100.00 Extra: NulL*************************** 2. row *************************** ID: 1 select_type: SIMPLE table: a partitions: NulL type: eq_refpossible_keys: PRIMARY key: PRIMARY key_len: 2 ref: sakila.b.film_ID rows: 1 filtered: 100.00 Extra: Using where2 rows in set,1 warning (0.03 sec)
MysqL实例6.type=const/system
,单表中最多有一个匹配行,查起来非常迅速,所以这个匹配行中的其他列的值可以被优化器在当前查询中当作常量来处理,例如,根据主键 primary key
或者唯一索引 unique index
进行查询.
MysqL实例MysqL> create table test_const ( -> test_ID int,-> test_context varchar(10),-> primary key (`test_ID`),-> ); insert into test_const values(1,'hello');explain select * from ( select * from test_const where test_ID=1 ) a \G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: test_const partitions: NulL type: constpossible_keys: PRIMARY key: PRIMARY key_len: 4 ref: const rows: 1 filtered: 100.00 Extra: NulL 1 row in set,1 warning (0.00 sec)
MysqL实例7.type=null
,MysqL 不用访问表或者索引,直接就能够得到结果:
MysqL实例MysqL> explain select 1 from dual where 1 \G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: NulL partitions: NulL type: NulLpossible_keys: NulL key: NulL key_len: NulL ref: NulL rows: NulL filtered: NulL Extra: No tables used1 row in set,1 warning (0.00 sec)
MysqL实例 类型 type 还有其他值,如 ref_or_null
(与 ref 类似,区别在于条件中包含对 null 的查询)、index_merge(索引合并优化)、unique_subquery (in 的后面是一个查询主键字段的子查询)、index_subquery(与 unique_subquery 类似,区别在于 in 的后面是查询非唯一索引字段的子查询)等.
MysqL实例show warnings 命令
MysqL实例执行explain 后再执行 show warnings
,可以看到sql 真正被执行之前优化器做了哪些 sql 改写:
MysqL实例MysqL [sakila]> explain select sum(amount) from customer a,payment b where 1=1 and a.customer_ID = b.customer_ID and email = 'JANE.BENNETT@sakilacustomer.org'\G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: a partitions: NulL type: ALLpossible_keys: PRIMARY key: NulL key_len: NulL ref: NulL rows: 599 filtered: 10.00 Extra: Using where*************************** 2. row *************************** ID: 1 select_type: SIMPLE table: b partitions: NulL type: refpossible_keys: IDx_fk_customer_ID key: IDx_fk_customer_ID key_len: 2 ref: sakila.a.customer_ID rows: 26 filtered: 100.00 Extra: NulL2 rows in set,1 warning (0.00 sec)MysqL [sakila]> show warnings;+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Level | Code | Message |+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Note | 1003 | /* select#1 */ select sum(`sakila`.`b`.`amount`) AS `sum(amount)` from `sakila`.`customer` `a` join `sakila`.`payment` `b` where ((`sakila`.`b`.`customer_ID` = `sakila`.`a`.`customer_ID`) and (`sakila`.`a`.`email` = 'JANE.BENNETT@sakilacustomer.org')) |+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+1 row in set (0.00 sec)
MysqL实例从 warning 的 message 字段中能够看到优化器自动去除了 1=1 恒成立的条件,也就是说优化器在改写 sql 时会自动去掉恒成立的条件.
MysqL实例explain 命令也有对分区的支持.
MysqL实例MysqL [sakila]> CREATE table `customer_part` ( -> `customer_ID` smallint(5) unsigned NOT NulL auto_INCREMENT,-> `store_ID` tinyint(3) unsigned NOT NulL,-> `first_name` varchar(45) NOT NulL,-> `last_name` varchar(45) NOT NulL,-> `email` varchar(50) DEFAulT NulL,-> `address_ID` smallint(5) unsigned NOT NulL,-> `active` tinyint(1) NOT NulL DEFAulT '1',-> `create_date` datetime NOT NulL,-> `last_update` timestamp NulL DEFAulT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,-> PRIMARY KEY (`customer_ID`) -> -> ) partition by hash (customer_ID) partitions 8;query OK,0 rows affected (0.06 sec)MysqL [sakila]> insert into customer_part select * from customer;query OK,599 rows affected (0.06 sec)Records: 599 Duplicates: 0 Warnings: 0MysqL [sakila]> explain select * from customer_part where customer_ID=130\G*************************** 1. row *************************** ID: 1 select_type: SIMPLE table: customer_part partitions: p2 type: constpossible_keys: PRIMARY key: PRIMARY key_len: 2 ref: const rows: 1 filtered: 100.00 Extra: NulL1 row in set,1 warnings (0.00 sec)
MysqL实例可以看到 sql 访问的分区是 p2.
MysqL实例四、通过 performance_schema 分析 sql 性能
MysqL实例旧版本的 MysqL 可以使用 profiles 分析 sql 性能,我用的是5.7.18的版本,已经不允许使用 profiles 了,推荐用
performance_schema 分析sql.
MysqL实例五、通过 trace 分析优化器如何选择执行计划.
MysqL实例MysqL5.6 提供了对 sql 的跟踪 trace,可以进一步了解为什么优化器选择 A 执行计划而不是 B 执行计划,帮助我们更好的理解优化器的行为.
MysqL实例使用方式:首先打开 trace,设置格式为 Json,设置 trace 最大能够使用的内存大小,避免解析过程中因为默认内存过小而不能够完整显示.
MysqL实例MysqL [sakila]> set optimizer_trace="enabled=on",end_markers_in_Json=on;query OK,0 rows affected (0.00 sec)MysqL [sakila]> set optimizer_trace_max_mem_size=1000000;query OK,0 rows affected (0.00 sec)
MysqL实例接下来执行想做 trace 的 sql 语句,例如像了解租赁表 rental 中库存编号 inventory_ID 为 4466 的电影拷贝在出租日期 rental_date 为 2005-05-25 4:00:00 ~ 5:00:00 之间出租的记录:
MysqL实例MysqL> select rental_ID from rental where 1=1 and rental_date >= '2005-05-25 04:00:00' and rental_date <= '2005-05-25 05:00:00' and inventory_ID=4466;+-----------+| rental_ID |+-----------+| 39 |+-----------+1 row in set (0.06 sec)MysqL [sakila]> select * from information_schema.optimizer_trace\G*************************** 1. row *************************** query: select * from infomation_schema.optimizer_trace TRACE: { "steps": [ ] /* steps */}MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0 INSUFFICIENT_PRIVILEGES: 01 row in set (0.00 sec)
MysqL实例六、 确定问题并采取相应的优化措施
MysqL实例经过以上步骤,基本就可以确认问题出现的原因.此时可以根据情况采取相应的措施,进行优化以提高执行的效率.
MysqL实例总结
MysqL实例以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对内存溢出PHP的支持.
总结以上是内存溢出为你收集整理的Mysql应用sql语句优化的一般步骤详解全部内容,希望文章能够帮你解决Mysql应用sql语句优化的一般步骤详解所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)