mySQL语句优化

 1.mysql语句优化之找出问题

在查询语句前加一个 EXPLAIN 关键字可以让我们看到mysql如何使用索引来处理select语句以及连接表

 例如: 

 EXPLAIN
 SELECT
    tab.* 
FROM
    (
SELECT
    p.idxIccid AS idxIccid,
    p.idxViFiId AS bb,
    p.keyID as cc,
    eu.idxViFiId as dd,
    eu.alaisName AS alaisName,
    eu.bootFirstISP AS bootFirstISP,
    eu.contGetFailed AS contGetFailed,
    eu.monthUUWiFiData AS monthUUWiFiData,
    (
CASE
    
    WHEN eu.devState = 'E' THEN
    eu.ONLINE 
    WHEN eu.devState = 'N' THEN
    15 
    WHEN eu.devState = 'W' THEN
    16 
    WHEN eu.devState = 'D' THEN
    17 
    WHEN eu.devState = 'R' THEN
    18 
    WHEN eu.devState = 'F' THEN
    19 
END 
    ) AS ONLINE,
    eu.pwd AS pwd,
    eu.rateLimit AS rateLimit,
    eu.usageAttr AS usageAttr 
FROM
    tbViFiDevice eu
    LEFT JOIN tbSimPPort p ON eu.idxViFiId = p.idxViFiId 
    LEFT JOIN tbViFiDevGroup grp ON eu.idxDevGrpID =grp.keyDevGrpID 
WHERE
    1 = 1 
ORDER BY
    ( CASE WHEN ONLINE = 1 THEN 1 ELSE 0 END ) DESC 
    LIMIT 0,
    25
) AS tab

 2.结果展示

同样的语句我在不同的地方运行结果是不一样的

测试服务器无问题:

本地数据库无问题:

测试服务器有问题:

测试修好:

一对比就可以发现问题了,查询量大而有的索引没有用到。

既然是某个索引时而有用时而没用,那么就强制使用索引就行了:表  force index(强制要走的那个索引) 

//省略。。。
FROM
    tbViFiDevice eu
    LEFT JOIN tbSimPPort p force index(simPPort_index_idxViFiId)  ON p.idxViFiId = eu.idxViFiId
    LEFT JOIN tbViFiDevGroup grp ON grp.keyDevGrpID = eu.idxDevGrpID 
WHERE 
//省略。。。

自此问题解决。

 3. EXPLAIN数据解析

EXPLAIN列的解释:

table:显示这一行的数据是关于哪张表的

type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL

         type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
         一般来说,得保证查询至少达到range级别,最好能达到ref。

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:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况

 index: 这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)

 ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免

更详细资料请参照 

EXPLAIN列的解释 :  博客   

4.索引
4.1 建立索引
1. 表的主键、外键必须有索引;
2. 经常与其他表进行连接的表,在连接字段上应该建立索引,多表进行多字段连接,建议适当建立复合索引;
3. 索引应该建立在查询条件中进行比较的字段上,而不是建立在我们要找出来并且显示的字段上;
4. 在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要建立索引;

  4.2 索引失效

1、IN、OR子句会使索引失效。
2、使用IS NULL 或IS NOT NULL同样会限制索引的使用。因为NULL值并没有被索引定义。
3、条件字段使用函数和表达式
4、避免在索引列上使用计算
5、比较不匹配的数据类型(如varchar类型当整型用:string1=1236、带通配符(%)的like语句 (匹配第一位尽量不要用通配符)
7、Order by语句用表达式最好用(索引列)

 


索引失效:博客

 5. SHOW SESSION STATUS LIKE "Handler%" 分析查询语句

Handler_read_first:索引中第一条被读的次数。如果较高,它表示服务器正执行大量全索引扫描;例如,SELECT col1 FROM foo,假定col1有索引(这个值越低越好)。
Handler_read_key:如果索引正在工作,这个值代表一个行被索引值读的次数,如果值越低,表示索引得到的性能改善不高,因为索引不经常使用(这个值越高越好)。
Handler_read_next :按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,该值增加。
Handler_read_prev:按照键顺序读前一行的请求数。该读方法主要用于优化ORDER BY ... DESC。
Handler_read_rnd :根据固定位置读一行的请求数。如果你正执行大量查询并需要对结果进行排序该值较高。你可能使用了大量需要MySQL扫描整个表的查询或你的连接没有正确使用键。这个值较高,意味着运行效率低,应该建立索引来补救。
Handler_read_rnd_next:在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说明你的表索引不正确或写入的查询没有利用索引。
SHOW SESSION STATUS 详情参考: 博客 、博客

 

posted @ 2019-07-12 14:13  一个九  阅读(3750)  评论(0编辑  收藏  举报