MySQL--SQL语句优化--步骤

本是古典 何须时尚 2023-07-22 04:57 118阅读 0赞

首发网址:MySQL—SQL语句优化—步骤_IT利刃出鞘的博客-CSDN博客

其他网址

SQL优化(一)、sql优化一般步骤_数据库_小浪与艳花-CSDN博客

概要步骤

sql优化一般步骤概要:

  1. 通过 show status 命令了解各种sql的执行频率
  2. 定位执行效率较低的sql语句
  3. 通过explain分析低效sql的执行计划
  4. 通过 show profile 分析sql
  5. 通过trace分析 优化器 如何选择执行计划
  6. 确定问题并采取相应的优化措施

show status 了解sql的执行频率

mysql客户端连接成功后,通过show[session|global] status命令,可以查看服务器的状态,如果不加默认为session(session级为当前连接的统计结果,global级为自数据库上次启动到现在的统计结果)。
示例: show status like ‘Com_%’;

70

com_xx表示每个xx语句的执行次数,通常着重看curd操作次数(这些参数适用于所有存储引擎);

Com_insert:执行select操作的次数,一次查询只累加1;
Com_select:执行insert操作的次数,批量插入的insert操作只累加一次;
Com_delete:执行update操作次数,提交和回滚均会累加;
Com_update:执行delete操作次数。

针对innodb存储引擎的表操作,累加的算法。比如:show status like ‘Innodb_rows_%’;

70 1

Innodb_rows_deleted :执行delete操作删除的行数;
Innodb_rows_inserted:执行insert操作插入的行数;
Innodb_rows_read :select查询返回的函数;
Innodb_rows_updated: update操作更新的函数。
通过截图,可以了解到当前数据库是以插入和查询为主,以及各种类型操作的执行比例。
对于事务型的应用,通过com_commit 和com_rollback可以了解事务提交和回滚的情况,对于回滚特别频繁的操作,可能意味着代码编写有问题。

以下操作用户了解数据库的基本情况:
show status like ‘connections’;— 试图连接mysql数据库的次数
show status like ‘uptime’;— 服务器工作时间
show status like ‘slow_queries’; – 慢查询的次数

定位执行效率较低的sql语句

通过慢查询日志定位哪些sql执行效率低下,用–log-slow-queries[=file_name]选项启动时,mysqld写一个包含所有执行时间超过long_query_time 秒的sql语句的日志文件,具体可参看后面的日志管理部分。

慢查询日志在查询结束以后才记录,所以在应用反正执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用show processlist命令查看当前mysql在进行的线程,包括线程的状态,是否锁表等,可以实时查看sql的执行情况,同时对一些锁表操作进行优化。

  1. mysql> show processlist;
  2. +------+------+-----------+------+---------+------+-------+------------------+
  3. | Id | User | Host | db | Command | Time | State | Info |
  4. +------+------+-----------+------+---------+------+-------+------------------+
  5. | 1619 | root | localhost | wq | Query | 0 | init | show processlist |
  6. +------+------+-----------+------+---------+------+-------+------------------+
  7. 1 row in set (0.00 sec)

通过explain分析低效sql的执行计划

追查到效率低的sql后,可以通过explain或desc命令获取mysql如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序,eg:统计某个email为租赁电影拷贝所支付的总金额,需要关联客户表customer和付款表payment,并且对付款金额amount字段做求和操作,相应sql的执行计划如下:

  1. 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

通过 show profile 分析sql

show profile可以在sql优化时告诉我们时间主要浪费在哪了。从5.0.37版本开始增加了对show profiles 和show profile的语句支持。通过having_profiling参数,可以看到sql是否支持profile。

  1. mysql> select @@have_profiling;
  2. +------------------+
  3. | @@have_profiling |
  4. +------------------+
  5. | YES |
  6. +------------------+
  7. 1 row in set, 1 warning (0.00 sec)

默认profiling是关闭的,可以通过set语句在session级别开启profiling:

  1. mysql> select @@profiling;
  2. +-------------+
  3. | @@profiling |
  4. +-------------+
  5. | 0 |
  6. +-------------+
  7. 1 row in set, 1 warning (0.00 sec)

可以直接set其值为1

  1. mysql> set profiling=1;
  2. Query OK, 0 rows affected, 1 warning (0.00 sec)

通过profile我们可以大致了解sql执行的过程。例如myisam表有表元数据的缓存(比如行数,即count(*)值),那么对一个myisam表的count(*)是不需要消耗太多资源的,而对于innodb来说,就没有这种元数据缓存,count(*)执行的较慢。下面来做个试验验证下。
首先,在一个innodb引擎的付款表payment上,执行一个count(*)查询:

  1. mysql> select count(*) from payment;
  2. +----------+
  3. | count(*) |
  4. +----------+
  5. | 16049 |
  6. +----------+
  7. 1 row in set (0.00 sec)

执行完毕后,通过show profiles语句,看到当前sql的query id为1:

  1. mysql> show profiles;
  2. +----------+------------+------------------------------+
  3. | Query_ID | Duration | Query |
  4. +----------+------------+------------------------------+
  5. | 1 | 0.00372550 | select count(*) from payment |
  6. +----------+------------+------------------------------+
  7. 1 row in set, 1 warning (0.00 sec)

通过show profile for query 1;语句能够看到执行过程中线程的每个状态和消耗的时间:

  1. mysql> show profile for query 1;
  2. +----------------------+----------+
  3. | Status | Duration |
  4. +----------------------+----------+
  5. | starting | 0.000082 |
  6. | checking permissions | 0.000008 |
  7. | Opening tables | 0.000022 |
  8. | init | 0.000017 |
  9. | System lock | 0.000008 |
  10. | optimizing | 0.000006 |
  11. | statistics | 0.000014 |
  12. | preparing | 0.000012 |
  13. | executing | 0.000003 |
  14. | Sending data | 0.003496 |
  15. | end | 0.000007 |
  16. | query end | 0.000006 |
  17. | closing tables | 0.000010 |
  18. | freeing items | 0.000011 |
  19. | cleaning up | 0.000025 |
  20. +----------------------+----------+
  21. 15 rows in set, 1 warning (0.00 sec)

状态值为sending data表示mysql线程开始访问数据行并把结果返回给客户端之前,mysql线程要做大良的磁盘读取操作,所以会导致在整个查询中耗时最长的状态。
通过执行show profile for query,可以看到在执行count(*)操作的过程中,时间耗费在状态值为sending data 上,通过查询 information_schema.profiling表并按照时间做个desc排序:

  1. mysql> select state,sum(duration) as total_r,round(100*sum(duration)/(select sum(duration) from information_schema.profiling where query_id=@query_id),2) as pct_r,count(*) as calls,sum(duration)/count(*) as "R/Call" from information_schema.profiling where query_id=@query_id group by state order by total_r desc;
  2. +----------------------+----------+-------+-------+--------------+
  3. | state | total_r | pct_r | calls | R/Call |
  4. +----------------------+----------+-------+-------+--------------+
  5. | Sending data | 0.003496 | 93.80 | 1 | 0.0034960000 |
  6. | starting | 0.000082 | 2.20 | 1 | 0.0000820000 |
  7. | cleaning up | 0.000025 | 0.67 | 1 | 0.0000250000 |
  8. | Opening tables | 0.000022 | 0.59 | 1 | 0.0000220000 |
  9. | init | 0.000017 | 0.46 | 1 | 0.0000170000 |
  10. | statistics | 0.000014 | 0.38 | 1 | 0.0000140000 |
  11. | preparing | 0.000012 | 0.32 | 1 | 0.0000120000 |
  12. | freeing items | 0.000011 | 0.30 | 1 | 0.0000110000 |
  13. | closing tables | 0.000010 | 0.27 | 1 | 0.0000100000 |
  14. | System lock | 0.000008 | 0.21 | 1 | 0.0000080000 |
  15. | checking permissions | 0.000008 | 0.21 | 1 | 0.0000080000 |
  16. | end | 0.000007 | 0.19 | 1 | 0.0000070000 |
  17. | query end | 0.000006 | 0.16 | 1 | 0.0000060000 |
  18. | optimizing | 0.000006 | 0.16 | 1 | 0.0000060000 |
  19. | executing | 0.000003 | 0.08 | 1 | 0.0000030000 |
  20. +----------------------+----------+-------+-------+--------------+
  21. 15 rows in set (0.00 sec)

获取到最消耗时间的线程状态后,mysql进一步选择all,cpu,block io,context switch,page faults等明细类型来查看mysql在使用什么资源上耗费了过高的时间,例如,选择查看cpu的耗费时间:

  1. mysql> show profile cpu for query 1;
  2. +----------------------+----------+----------+------------+
  3. | Status | Duration | CPU_user | CPU_system |
  4. +----------------------+----------+----------+------------+
  5. | starting | 0.000065 | 0.000027 | 0.000028 |
  6. | checking permissions | 0.000007 | 0.000003 | 0.000004 |
  7. | Opening tables | 0.000021 | 0.000011 | 0.000011 |
  8. | init | 0.000014 | 0.000007 | 0.000007 |
  9. | System lock | 0.000009 | 0.000004 | 0.000005 |
  10. | optimizing | 0.000007 | 0.000003 | 0.000003 |
  11. | statistics | 0.000013 | 0.000007 | 0.000007 |
  12. | preparing | 0.000012 | 0.000005 | 0.000006 |
  13. | executing | 0.000003 | 0.000002 | 0.000002 |
  14. | Sending data | 0.003683 | 0.003684 | 0.000000 |
  15. | end | 0.000007 | 0.000006 | 0.000000 |
  16. | query end | 0.000006 | 0.000006 | 0.000000 |
  17. | closing tables | 0.000009 | 0.000009 | 0.000000 |
  18. | freeing items | 0.000010 | 0.000010 | 0.000000 |
  19. | cleaning up | 0.000014 | 0.000014 | 0.000000 |
  20. +----------------------+----------+----------+------------+
  21. 15 rows in set, 1 warning (0.00 sec)

可想而知,sending data状态值大的原因为时间主要耗费在cpu的操作上了,对比myisam表的count(*)操作,也创建一个同样表结构的myisam表,数据量也完全一致。

  1. mysql> create table payment_myisam like payment;
  2. Query OK, 0 rows affected (0.04 sec)
  3. mysql> alter table payment_myisam engine=myisam;
  4. Query OK, 0 rows affected (0.04 sec)
  5. Records: 0 Duplicates: 0 Warnings: 0
  6. mysql> insert into payment_myisam select * from payment;
  7. Query OK, 16049 rows affected (0.08 sec)
  8. Records: 16049 Duplicates: 0 Warnings: 0

执行count(*),显示profile:

  1. mysql> select count(*) from payment_myisam;
  2. +----------+
  3. | count(*) |
  4. +----------+
  5. | 16049 |
  6. +----------+
  7. 1 row in set (0.00 sec)
  8. mysql> show profiles;
  9. +----------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
  10. | Query_ID | Duration | Query |
  11. +----------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
  12. | 1 | 0.00016550 | select @@have_profiling |
  13. | 2 | 0.00387925 | select count(*) from payment |
  14. | 3 | 0.00005900 | show profile context switch for query 2 |
  15. | 4 | 0.00007175 | create table payment_myisam lkike payment |
  16. | 5 | 0.04542150 | create table payment_myisam like payment |
  17. | 6 | 0.03682200 | alter table payment_myisam engine=myisam |
  18. | 7 | 0.08007525 | insert into payment_myisam select * from payment |
  19. | 8 | 0.00005425 | mysql> create table payment_myisam like payment |
  20. | 9 | 0.00005275 | Query OK, 0 rows affected (0.04 sec)
  21. mysql> alter table payment_myisam engine=myisam |
  22. | 10 | 0.00005300 | Query OK, 0 rows affected (0.04 sec)
  23. Records: 0 Duplicates: 0 Warnings: 0
  24. mysql> insert into payment_myisam select * from payment |
  25. | 11 | 0.00006350 | Query OK, 16049 rows affected (0.08 sec)
  26. Records: 16049 Duplicates: 0 Warnings: 0 |
  27. | 12 | 0.00016450 | select count(*) from payment_myisam |
  28. +----------+------------+--------------------------------------------------------------------------------------------------------------------------------------+
  29. 12 rows in set, 1 warning (0.00 sec)
  30. mysql> show profile for query 12;
  31. +----------------------+----------+
  32. | Status | Duration |
  33. +----------------------+----------+
  34. | starting | 0.000063 |
  35. | checking permissions | 0.000007 |
  36. | Opening tables | 0.000020 |
  37. | init | 0.000014 |
  38. | System lock | 0.000009 |
  39. | optimizing | 0.000008 |
  40. | executing | 0.000010 |
  41. | end | 0.000004 |
  42. | query end | 0.000004 |
  43. | closing tables | 0.000009 |
  44. | freeing items | 0.000008 |
  45. | cleaning up | 0.000012 |
  46. +----------------------+----------+
  47. 12 rows in set, 1 warning (0.00 sec)

由上面两种引擎所建表的count(*)操作后,执行profile可看出,innodb引擎的表由sending data状态,存在访问数据即磁盘读取的过程,时间主要耗费在cpu上,而myisam引擎的表在executing之后就结束查询,意味着不需要去访问数据。
如果对mysql源码感兴趣,可以通过show profile source for query查看sql解析执行过程中的每个步骤对应的源码文件、函数名称、具体源文件行数:

  1. mysql> show profile source for query 1;
  2. +----------------------+----------+-----------------------+------------------+-------------+
  3. | Status | Duration | Source_function | Source_file | Source_line |
  4. +----------------------+----------+-----------------------+------------------+-------------+
  5. | starting | 0.000065 | NULL | NULL | NULL |
  6. | checking permissions | 0.000007 | check_access | sql_parse.cc | 5350 |
  7. | Opening tables | 0.000021 | open_tables | sql_base.cc | 5095 |
  8. | init | 0.000014 | mysql_prepare_select | sql_select.cc | 1051 |
  9. | System lock | 0.000009 | mysql_lock_tables | lock.cc | 304 |
  10. | optimizing | 0.000007 | optimize | sql_optimizer.cc | 139 |
  11. | statistics | 0.000013 | optimize | sql_optimizer.cc | 365 |
  12. | preparing | 0.000012 | optimize | sql_optimizer.cc | 488 |
  13. | executing | 0.000003 | exec | sql_executor.cc | 110 |
  14. | Sending data | 0.003683 | exec | sql_executor.cc | 190 |
  15. | end | 0.000007 | mysql_execute_select | sql_select.cc | 1106 |
  16. | query end | 0.000006 | mysql_execute_command | sql_parse.cc | 5049 |
  17. | closing tables | 0.000009 | mysql_execute_command | sql_parse.cc | 5097 |
  18. | freeing items | 0.000010 | mysql_parse | sql_parse.cc | 6486 |
  19. | cleaning up | 0.000014 | dispatch_command | sql_parse.cc | 1815 |
  20. +----------------------+----------+-----------------------+------------------+-------------+
  21. 15 rows in set, 1 warning (0.00 sec)

通过trace分析优化器如何选择执行计划

mysql5.6是通过trace文件进一步告诉我们优化器是如何选择执行计划的。(即mysql5.6提供了对sql的跟踪trace文件,从而得知优化器为何选择a执行计划而不选择b执行计划,有助于我们理解优化器的行为。)

首先打开trace,设置格式为json,设置trace最大能够使用内存的大小,避免解析过程中因为默认内存过小不能完全显示:

  1. mysql> set optimizer_trace="enabled=on" ,end_markers_in_json=on;
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> set optimizer_trace_max_mem_size=1000000;
  4. Query OK, 0 rows affected (0.00 sec)

然后执行下想做追踪的sql语句,eg:租赁表中rental的库存编号inventory_id为4466的电影拷贝 ,出租日期rental_date 在2005-05-25 4:00:00~5:00:00范围内的出租记录,最后通过检查语句select * from information_schema.optimizer_trace就可以知道mysql如何执行sql的。

  1. 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;
  2. +-----------+
  3. | rental_id |
  4. +-----------+
  5. | 39 |
  6. +-----------+
  7. 1 row in set (0.00 sec)
  8. mysql> select * from information_schema.optimizer_trace\G
  9. *************************** 1. row ***************************
  10. QUERY: 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
  11. TRACE: {
  12. "steps": [
  13. {
  14. "join_preparation": {
  15. "select#": 1,
  16. "steps": [
  17. {
  18. "expanded_query": "/* select#1 */ select `rental`.`rental_id` AS `rental_id` from `rental` where ((1 = 1) and (`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00') and (`rental`.`inventory_id` = 4466))"
  19. }
  20. ] /* steps */
  21. } /* join_preparation */
  22. },
  23. {
  24. "join_optimization": {
  25. "select#": 1,
  26. "steps": [
  27. {
  28. "condition_processing": {
  29. "condition": "WHERE",
  30. "original_condition": "((1 = 1) and (`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00') and (`rental`.`inventory_id` = 4466))",
  31. "steps": [
  32. {
  33. "transformation": "equality_propagation",
  34. "resulting_condition": "((1 = 1) and (`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00') and multiple equal(4466, `rental`.`inventory_id`))"
  35. },
  36. {
  37. "transformation": "constant_propagation",
  38. "resulting_condition": "((1 = 1) and (`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00') and multiple equal(4466, `rental`.`inventory_id`))"
  39. },
  40. {
  41. "transformation": "trivial_condition_removal",
  42. "resulting_condition": "((`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00') and multiple equal(4466, `rental`.`inventory_id`))"
  43. }
  44. ] /* steps */
  45. } /* condition_processing */
  46. },
  47. {
  48. "table_dependencies": [
  49. {
  50. "table": "`rental`",
  51. "row_may_be_null": false,
  52. "map_bit": 0,
  53. "depends_on_map_bits": [
  54. ] /* depends_on_map_bits */
  55. }
  56. ] /* table_dependencies */
  57. },
  58. {
  59. "ref_optimizer_key_uses": [
  60. {
  61. "table": "`rental`",
  62. "field": "inventory_id",
  63. "equals": "4466",
  64. "null_rejecting": false
  65. }
  66. ] /* ref_optimizer_key_uses */
  67. },
  68. {
  69. "rows_estimation": [
  70. {
  71. "table": "`rental`",
  72. "range_analysis": {
  73. "table_scan": {
  74. "rows": 16008,
  75. "cost": 3300.7
  76. } /* table_scan */,
  77. "potential_range_indices": [
  78. {
  79. "index": "PRIMARY",
  80. "usable": false,
  81. "cause": "not_applicable"
  82. },
  83. {
  84. "index": "rental_date",
  85. "usable": true,
  86. "key_parts": [
  87. "rental_date",
  88. "inventory_id",
  89. "customer_id"
  90. ] /* key_parts */
  91. },
  92. {
  93. "index": "idx_fk_inventory_id",
  94. "usable": true,
  95. "key_parts": [
  96. "inventory_id",
  97. "rental_id"
  98. ] /* key_parts */
  99. },
  100. {
  101. "index": "idx_fk_customer_id",
  102. "usable": false,
  103. "cause": "not_applicable"
  104. },
  105. {
  106. "index": "idx_fk_staff_id",
  107. "usable": false,
  108. "cause": "not_applicable"
  109. }
  110. ] /* potential_range_indices */,
  111. "best_covering_index_scan": {
  112. "index": "rental_date",
  113. "cost": 3229.9,
  114. "chosen": true
  115. } /* best_covering_index_scan */,
  116. "setup_range_conditions": [
  117. ] /* setup_range_conditions */,
  118. "group_index_range": {
  119. "chosen": false,
  120. "cause": "not_group_by_or_distinct"
  121. } /* group_index_range */,
  122. "analyzing_range_alternatives": {
  123. "range_scan_alternatives": [
  124. {
  125. "index": "rental_date",
  126. "ranges": [
  127. "2005-05-25 04:00:00 <= rental_date <= 2005-05-25 05:00:00"
  128. ] /* ranges */,
  129. "index_dives_for_eq_ranges": true,
  130. "rowid_ordered": false,
  131. "using_mrr": false,
  132. "index_only": true,
  133. "rows": 10,
  134. "cost": 3.0254,
  135. "chosen": true
  136. },
  137. {
  138. "index": "idx_fk_inventory_id",
  139. "ranges": [
  140. "4466 <= inventory_id <= 4466"
  141. ] /* ranges */,
  142. "index_dives_for_eq_ranges": true,
  143. "rowid_ordered": true,
  144. "using_mrr": false,
  145. "index_only": false,
  146. "rows": 5,
  147. "cost": 7.01,
  148. "chosen": false,
  149. "cause": "cost"
  150. }
  151. ] /* range_scan_alternatives */,
  152. "analyzing_roworder_intersect": {
  153. "usable": false,
  154. "cause": "too_few_roworder_scans"
  155. } /* analyzing_roworder_intersect */
  156. } /* analyzing_range_alternatives */,
  157. "chosen_range_access_summary": {
  158. "range_access_plan": {
  159. "type": "range_scan",
  160. "index": "rental_date",
  161. "rows": 10,
  162. "ranges": [
  163. "2005-05-25 04:00:00 <= rental_date <= 2005-05-25 05:00:00"
  164. ] /* ranges */
  165. } /* range_access_plan */,
  166. "rows_for_plan": 10,
  167. "cost_for_plan": 3.0254,
  168. "chosen": true
  169. } /* chosen_range_access_summary */
  170. } /* range_analysis */
  171. }
  172. ] /* rows_estimation */
  173. },
  174. {
  175. "considered_execution_plans": [
  176. {
  177. "plan_prefix": [
  178. ] /* plan_prefix */,
  179. "table": "`rental`",
  180. "best_access_path": {
  181. "considered_access_paths": [
  182. {
  183. "access_type": "ref",
  184. "index": "idx_fk_inventory_id",
  185. "rows": 5,
  186. "cost": 6,
  187. "chosen": true
  188. },
  189. {
  190. "access_type": "range",
  191. "rows": 5,
  192. "cost": 5.0254,
  193. "chosen": true
  194. }
  195. ] /* considered_access_paths */
  196. } /* best_access_path */,
  197. "cost_for_plan": 5.0254,
  198. "rows_for_plan": 5,
  199. "chosen": true
  200. }
  201. ] /* considered_execution_plans */
  202. },
  203. {
  204. "attaching_conditions_to_tables": {
  205. "original_condition": "((`rental`.`inventory_id` = 4466) and (`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00'))",
  206. "attached_conditions_computation": [
  207. ] /* attached_conditions_computation */,
  208. "attached_conditions_summary": [
  209. {
  210. "table": "`rental`",
  211. "attached": "((`rental`.`inventory_id` = 4466) and (`rental`.`rental_date` >= '2005-05-25 04:00:00') and (`rental`.`rental_date` <= '2005-05-25 05:00:00'))"
  212. }
  213. ] /* attached_conditions_summary */
  214. } /* attaching_conditions_to_tables */
  215. },
  216. {
  217. "refine_plan": [
  218. {
  219. "table": "`rental`",
  220. "access_type": "range"
  221. }
  222. ] /* refine_plan */
  223. }
  224. ] /* steps */
  225. } /* join_optimization */
  226. },
  227. {
  228. "join_execution": {
  229. "select#": 1,
  230. "steps": [
  231. ] /* steps */
  232. } /* join_execution */
  233. }
  234. ] /* steps */
  235. }
  236. MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
  237. INSUFFICIENT_PRIVILEGES: 0
  238. 1 row in set (0.00 sec)

确定问题并采取相应的优化措施

经过以上操作,基本可以定位问题出现的原因。此时可以根据实际情况采取相应措施,通过优化来提高执行的效率。比如在第三点提到的低效sql的执行计划,已经确认是对客户表customer的权标扫描导致效率不理想,我们可以通过对email创建索引来提高效率。

  1. mysql> create index idx_email on customer(email);
  2. Query OK, 0 rows affected, 1 warning (0.05 sec)
  3. Records: 0 Duplicates: 0 Warnings: 1
  4. mysql> 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
  5. *************************** 1. row ***************************
  6. id: 1
  7. select_type: SIMPLE
  8. table: a
  9. type: const
  10. possible_keys: PRIMARY,uk_email,idex_email,idx_email
  11. key: uk_email
  12. key_len: 153
  13. ref: const
  14. rows: 1
  15. Extra: Using index
  16. *************************** 2. row ***************************
  17. id: 1
  18. select_type: SIMPLE
  19. table: b
  20. type: ref
  21. possible_keys: idx_fk_customer_id
  22. key: idx_fk_customer_id
  23. key_len: 2
  24. ref: const
  25. rows: 28
  26. Extra: NULL
  27. 2 rows in set (0.00 sec)

对比第3点,可以看出建立索引对customer表需要扫描的行数rows变少,性能有所提升(根据类型判断性能:由all变为const),可见索引的使用可以大大提高数据库的访问速度,尤其表越大效率越明显。

发表评论

表情:
评论列表 (有 0 条评论,118人围观)

还没有评论,来说两句吧...

相关阅读

    相关 mysqlsql执行顺序

    mysql语句的执行顺序问题 这是先执行ORDERBY语句,大多数的你想找前N条记录的时候LIMIT都会最后执行,因为如果不是这样的话就不会达到你想要的记录 本回答由提

    相关 sql 语句优化

    sql 语句优化   1.      对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。   2.应尽量避免在

    相关 SQL语句优化

    [SQL语句优化][SQL]   怎么加快查询速度,优化查询效率,主要原则就是应尽量避免全表扫描,应该考虑在where及order by 涉及的列上建立索引。   建立