深入浅出Mysql - 优化篇(索引)

SQL优化

通过show status了解各种sql执行的频率

	mysql> show status like 'Innodb_rows_%';
	+----------------------+--------------+
	| Variable_name        | Value        |
	+----------------------+--------------+
	| Innodb_rows_deleted  | 163063       |
	| Innodb_rows_inserted | 9974483      |
	| Innodb_rows_read     | 299261731677 |
	| Innodb_rows_updated  | 19791454     |
	+----------------------+--------------+
	4 rows in set (0.04 sec)
	mysql> show status like 'Com_%';
	+---------------------------------+-------+
	| Variable_name                   | Value |
	+---------------------------------+-------+
	| Com_admin_commands              | 0     |
	| Com_assign_to_keycache          | 0     |
	| Com_alter_db                    | 0     |
	| Com_alter_db_upgrade            | 0     |
	| Com_alter_event                 | 0     |
	| Com_alter_function              | 0     |
	| Com_alter_procedure             | 0     |
	| Com_alter_server                | 0     |
	| Com_alter_table                 | 0     |
	| Com_alter_tablespace            | 0     |
	| Com_alter_user                  | 0     |
	| Com_analyze                     | 0     |
	| ....   						  |       |
	+---------------------------------+-------+
	159 rows in set (0.18 sec)
  • Com_select:执行SELECT操作的次效,一次查询只累加1
  • Com_insert:执行INSERT操作的次数,对于批费插入的INSERT操作,只累加一次
  • Com_update:执行UPDATE操作的次数
  • Com delete:执行DELETE操作的次数.
  • Innodb_rows_read: SELECT i询返回的行数
  • Innodb_rows_mserted:执行INSERT操作插入的行数
  • Inoodb_rows_dated:执行UPDATE操作更新的行教
  • Innodb_rows_deleted:执行DELETE操作则除的行数

通过以上几个参数,可以很容易地了解当前数据库的应用是以插入更新为主还是以查询操作为主,以及各种类型的SQL大致的执行比例是多少。对于更新操作的计数,是对执行次数?的计数,不论提交还是回滚都会进行累加。

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

  • 通过慢查询日志定位那些执行效率较低的SQL语句,-log-slow-queries[= file_name]选项启动时,mysqld写一个包含所有执行时间超过long_query_time秒的SQL语句的日志文件

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

通过EXPLAIN分析低效SQL的执行计划

通过以上步骤查询到效率低的SQL语句后,可以通过EXPLAIN或者DESC命令获取?MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。

mysql> explain select * from fa_order limit 0,10; \G
+----+-------------+----------+------+---------------+------+---------+------+---------+-------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra |
+----+-------------+----------+------+---------------+------+---------+------+---------+-------+
|  1 | SIMPLE      | fa_order | ALL  | NULL          | NULL | NULL    | NULL | 5076272 |       |
+----+-------------+----------+------+---------------+------+---------+------+---------+-------+
1 row in set (0.03 sec)
  • sdect_type:表示SELECT的类型,常见的取值有SIMPLE (简单表,即不使用表连?接或者子查询)、PRIMARY (主查询,即外层的查询)、UNION (UNION中的第二个或者后面?的查询语句),SUBQUERY (子查询中的第一个SELECT)等。

  • table:输出诂果集的表.

  • possible_keys:表示查询时可能使用的索引.

  • key:表示实际使用的索引

  • key_len:使用到索引字段的长度

  • rows:扫描行的数量

  • Extra:执行情况的说明和描迅 包舍不适合在其他列中显示但是对执行计划非常重要的额外信息

  • type:表示MySQL在表中找到所需行的方式,或者叫访问类型。

	+------+-------------+----------+------+---------------+---------------+------+
	|  ALL | index       | range    | ref  | eq_ref        | const, system | NULL |
	+------+-------------+----------+------+---------------+---------------+------+
	
	从左至右,性能由最差到最好。

① type = ALL,全表扫描,MySQL遍历全妹找到匹配的行。

② type=index,索引全扫描,MySQL遍历整个索引来查询匹配的行。

③ type=range,索引范围扫描,常见于V、<=^ >、x=、between等操作符

④ type=ref,使用非唯一索引扫描或唯一索引的前缀扫描,返回匹配某个单独值的记录行

⑤ type=eq_ref,类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只?有一条记录匹配;简单来说,就是多表连接中使用primary key或者unique index作为关联条件。

⑥ type=consVsystem,单表中最多有一个匹配行,查询起来非常迅速,所以这个匹配行中的其他列的值可以被优化器在当前查询中当作常量来处理,例如,根据主键primary key或者唯一索引unique index进行的查询。

通过唯一索引uk_email访问的时候,类型type为const;而从我们构造的仅有一条记录的?a表中检索时,类型type就为system。

explain extended输出结果中多了 filtered字段,同时从warning的message字段能够看到优?化器自动去除了 1=1恒成立的条件,也就是说优化器在改写SQL时会自动去掉恒成立的条件。?在遇到复杂的SQL时,我们可以利用explain extended的结果来迅速地获取一个更清晰易读的SQL。

MySQL 5.1开始支持分区功能,同时explain命令也増加了对分区的支持。可以通过explain partitions命令查看SQL所访问的分区。

索引优化

索引是数据库优化中最常用也是最重要的手段之一,通过索引通常可以帮助用户解决大多数的SQL性能问题。

索引是在MySQL的存储引华层中实现的,而不是在服务器层实现的。所以每种存储引擎?的索引都不一定完全相同,也不是所有的存储引擎都支持所有的索引类型。MySQL目前提供了以下4种索引。

  • B-Tree索引:景常见的索引类型,大部分引擎都支持B树索引。
  • HASH索引:只有Memory引擎支持,使用场景简单。
  • R-Tree索引(空间索引):空间索引是MylSAM的一个特珠索引类型,主要用于地理?空间数据类型,通常使用较少,不做特别介绍。
  • Full-text (全丈索引):全文索引也是MylSAM的一个特珠索引类型,主要用于全文?索引,InnoDB从MySQL5.6版本开始提供对全文索引的支持。

mysql如何使用索引

B-Tree索引是最常见的索引,构造类似二叉树,能根据键值提供一行或者一个行集的快速访问,通常只需要很少的读操作就可以找到正确的行。不过,需要注意&Tree索引中的B不代表二叉树(binary),而是代表平衡树(balanced)。B-Tree索引并不是一棵二叉树。

mysql中能够使用索引的典型场景

匹配全值(Match the full value),对索引中所有列都指定具体值,即是对索引中的所?有列都有等值匹配的条件。

mysql> explain select * from fa_order where order_no = 'stlad202006281753256428' and user_id = 5140595 ;
+----+-------------+----------+------+-----------------+---------+---------+-------+------+-------------+
| id | select_type | table    | type | possible_keys   | key     | key_len | ref   | rows | Extra       |
+----+-------------+----------+------+-----------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | fa_order | ref  | user_id,ordersn | ordersn | 243     | const |    1 | Using where |
+----+-------------+----------+------+-----------------+---------+---------+-------+------+-------------+
1 row in set (0.04 sec)

匹配值的范围查询(Match a range of values X对索引的值能够进行范围查找。

mysql> explain select * from fa_order where id >= 5277516 ;
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
|  1 | SIMPLE      | fa_order | range | PRIMARY       | PRIMARY | 8       | NULL | 2538137 | Using where |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
1 row in set (0.04 sec)

mysql> explain select * from fa_order where user_id >= 5277516 ;
+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | fa_order | ALL  | user_id       | NULL | NULL    | NULL | 5076275 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.04 sec)

注意:user_id 是普通索引,id是主键索引,id是range,user_id还是all???答:如果该id返回结果集有较多行,优化器会认为不如直接扫描聚集索引来得快。毕竟非聚集索引需要再利用聚集索引定位数据获得全量表,非聚集索引是指向聚集索引的,一般如果需要返回非聚集索引中不包括的字段,就需要再次扫描聚集索引。

匹配最左前缀(Match a leftmost prefix ),仅仅使用索引中的最左边列进行查找。

仅仅对索引进行查询(Index only query),当查询的列都在索引的字段中时,查询的效率更高

Extra部分变成了 Using index,也就意味着,现在直接访问索引就足够获取到所需要的数据,不需要通过索引回表,Using index也就是平常说的覆盖索引扫描。只访问必须访问的数据,?在一般情况下,减少不必要的数据访问能够提升效率。

匹配列前缀(Match a column prefix),仅仅使用索引中的第一列,并且只包含索引第一列的开头一部分进行查找。

mysql> explain select * from fa_order where order_no like 'ydy_%';
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | fa_order | range | ordersn       | ordersn | 243     | NULL |  336 | Using where |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.07 sec)

Extra 值为Using where 耘优化器需要通过索引回疝询数据,Using index 表示查询使用了覆盖索引扫描。

如果列名是索引,那么使用colunm name isnuU就会使用索引。

存在索引但不能使用使用索引的典型场景

① 以%开头的LIKE查询不能够利用B-Tree索引,执行计划中key的值为NULL表示没有使用索引。
② 数据类型出现隐式转换的时候也不会使用索引,特别是当列类型是字符串,那么一定记得在where条件中把字符常量值用引号引起来,否则即便这个列上有索引,MySQL也不会用到,因为MySQL默认把输入的常量值进行转换以后才进行检索。
③ 复合索引的情况下,假如查询条件不包含索引列最左边部分,即不满足最左原则,是不会使用复合索引的。
④ 如果MySQL估计使用索引比全表扫描更慢,则不使用索引。
⑤ 用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章