介绍一下MYSQL常用的优化技巧

2023-07-06   


MySQL 自带 slow log 的分析工具 mysqldumpslow ,但是没有说明。本文通过分析该脚本,介绍了其用法。
   slow log 是 MySQL 根据 SQL 语句的执行时间设定,写入的一个文件,用于分析执行较慢的语句。
  
   只要在 my.cnf 文件中配置好:
   log-slow-queries = [slow_query_log_filename]
   即可记录超过默认的 10s 执行时间的 SQL 语句。
   如果要修改默认设置,可以添加:
   long_query_time = 5
   设定为 5s 。
  
   如果要记录所有 SQL 语句,可以写入:
   log-long-format
  
   # t=time, l=lock time, r=rows
   # at, al, 以及 ar 是对应的平均值
  
   mysqldumpslow 可以接受的参数有:
   ‘v+’, # verbose
   ‘d+’, # debug
   ‘s=s’, # 排序 (t, at, l, al, r, ar etc)
   ‘r!’, # 倒排序 (largest last instead of first)
   ‘t=i’, # 显示最高的 n 个查询
   ‘a!’, # 不把所有的数字以 N ,字符串以 ‘S’ 显示
   ‘n=i’, # abstract numbers with at least n digits within names
   ‘g=s’, # grep: only consider stmts that include this string
   ‘h=s’, # hostname of db server for *-slow.log filename (can be wildcard)
   ‘i=s’, # name of server instance (if using mysql.server startup script)
   ‘l!’, # don’t subtract lock time from total time
  
   mysql explain的使用说明
   explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。
   使用方法,在select语句前加上explain就可以了:
   如:explain select surname,first_name form a,b where a.id=b.id
   分析结果形式如下:
   引用
  
   mysql> explain SELECT * FROM `whisper` WHERE to_id = 6696 AND del = 0 AND whisper=0 ORDER BY `send_time` DESC LIMIT 4;
   +—-+————-+———+——+—————+——-+———+——-+——+—————————–+
   | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
   +—-+————-+———+——+—————+——-+———+——-+——+—————————–+
   | 1 | SIMPLE | whisper | ref | to_id | to_id | 4 | const | 1 | Using where; Using filesort |
   +—-+————-+———+——+—————+——-+———+——-+——+—————————–+
   1 row in set (0.00 sec)
  
   EXPLAIN列的解释:
   table 显示这一行的数据是关于哪张表的
   type 这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL
   possible_keys 显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句
   key 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
   key_len 使用的索引的长度。在不损失精确性的情况下,长度越短越好
   ref 显示索引的哪一列被使用了,如果可能的话,是一个常数
   rows MYSQL认为必须检查的用来返回请求数据的行数
   Extra 关于MYSQL如何解析查询的额外信息。将在表4.3中讨论,但这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢
  
   extra 列返回的描述的意义
   Distinct 一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
   Not exists MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了
   Range checked for each
   Record(index map:#)没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
   Using filesort 看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行
   Using index 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候
   Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上
   Where used 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题
  
   不同连接类型的解释(按照效率高低的顺序排序)
   system 表只有一行:system表。这是const连接类型的特殊情况
   const 表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待
   eq_ref 在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用
   ref 这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好
   range 这个连接类型使用索引返回一个范围中的行,比如使用>或 200。我们永远无法找到一个既小于100又大于200的数。
   如果遇到这样的查询条件,再去执行这样的SQL语句就是多此一举。幸好MySQL可以自动检测这种情况。如我们可以看看如下的SQL语句:
   1. SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”
   以上的查询语句要查找NAME既等于name1又等于name2的记录。很明显,这是一个不可达的查询,WHERE条件一定是假。MySQL在执行 SQL语句之前,会先分析WHERE条件是否是不可达的查询,如果是,就不再执行这条SQL语句了。为了验证这一点。我们首先对如下的SQL使用 EXPLAIN进行测试:
   1. EXPLAIN SELECT * FROM SALES WHERE NAME = “name1”
   上面的查询是一个正常的查询,我们可以看到使用EXPLAIN返回的执行信息数据中table项是SALES。这说明MySQL对SALES进行操作了。再看看下面的语句:
   1. EXPLAIN SELECT * FROM SALES WHERE NAME = “name1” AND NAME = “name2”
   我们可以看到,table项是空,这说明MySQL并没有对SALES表进行操作。
   五、 使用各种查询选择来提高性能
   SELECT语句除了正常的使用外,MySQL还为我们提供了很多可以增强查询性能的选项。如上面介绍的用于控制查询缓冲的SQL_NO_CACHE和SQL_CACHE就是其中两个选项。在这一部分,我将介绍几个常用的查询选项。
   1. STRAIGHT_JOIN:强制连接顺序
   当我们将两个或多个表连接起来进行查询时,我们并不用关心MySQL先连哪个表,后连哪个表。而这一切都是由MySQL内部通过一系列的计算、评估,最后得出的一个连接顺序决定的。如下列的SQL语句中,TABLE1和TABLE2并不一定是谁连接谁:
   1. SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 ,TABLE2 WHERE …
   如果开发人员需要人为地干预连接的顺序,就得使用STRAIGHT_JOIN关键字,如下列的SQL语句:
   1. SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 STRAIGHT_JOIN TABLE2 WHERE …
   由上面的SQL语句可知,通过STRAIGHT_JOIN强迫MySQL按TABLE1、TABLE2的顺序连接表。如果你认为按自己的顺序比MySQL推荐的顺序进行连接的效率高的话,就可以通过STRAIGHT_JOIN来确定连接顺序。
   2. 干预索引使用,提高性能
   在上面已经提到了索引的使用。一般情况下,在查询时MySQL将自己决定是否使用索引,使用哪一个索引。但在一些特殊情况下,我们希望MySQL只使用一个或几个索引,或者不希望使用某个索引。这就需要使用MySQL的控制索引的一些查询选项。
   限制使用索引的范围
   有时我们在数据表里建立了很多索引,当MySQL对索引进行选择时,这些索引都在考虑的范围内。但有时我们希望MySQL只考虑几个索引,而不是全部的索引,这就需要用到USE INDEX对查询语句进行设置。
   1. SELECT * FROM TABLE1 USE INDEX (FIELD1, FIELD2) …
   从以上SQL语句可以看出,无论在TABLE1中已经建立了多少个索引,MySQL在选择索引时,只考虑在FIELD1和FIELD2上建立的索引。
   限制不使用索引的范围
   如果我们要考虑的索引很多,而不被使用的索引又很少时,可以使用IGNORE INDEX进行反向选取。在上面的例子中是选择被考虑的索引,而使用IGNORE INDEX是选择不被考虑的索引。
   1. SELECT * FROM TABLE1 IGNORE INDEX (FIELD1, FIELD2) …
   在上面的SQL语句中,TABLE1表中只有FIELD1和FIELD2上的索引不被使用。
   强迫使用某一个索引
   上面的两个例子都是给MySQL提供一个选择,也就是说MySQL并不一定要使用这些索引。而有时我们希望MySQL必须要使用某一个索引(由于 MySQL在查询时只能使用一个索引,因此只能强迫MySQL使用一个索引)。这就需要使用FORCE INDEX来完成这个功能。
   1. SELECT * FROM TABLE1 FORCE INDEX (FIELD1) …
   以上的SQL语句只使用建立在FIELD1上的索引,而不使用其它字段上的索引。
   3. 使用临时表提供查询性能
   当我们查询的结果集中的数据比较多时,可以通过SQL_BUFFER_RESULT.选项强制将结果集放到临时表中,这样就可以很快地释放MySQL的表锁(这样其它的SQL语句就可以对这些记录进行查询了),并且可以长时间地为客户端提供大记录集。
   1. SELECT SQL_BUFFER_RESULT * FROM TABLE1 WHERE …
   和SQL_BUFFER_RESULT.选项类似的还有SQL_BIG_RESULT,这个选项一般用于分组或DISTINCT关键字,这个选项通知MySQL,如果有必要,就将查询结果放到临时表中,甚至在临时表中进行排序。
   1. SELECT SQL_BUFFER_RESULT FIELD1, COUNT(*) FROM TABLE1 GROUP BY FIELD1


相关内容:

  1. 介绍一下如何优化MySql
  2. 简单叙述一下MYSQL的优化
  3. 介绍一下Mysql的存储引擎
  4. 介绍一下mysql的日期和时间函数
  5. 一些关于MySql加速和优化的面试题
  6. mysql有关权限的表都有哪几个