zoukankan      html  css  js  c++  java
  • MySQL---正确使用索引、limit分页、执行计划、慢日志查询

    正确使用索引

    数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。
    即使建立索引,索引也不会生效:

     1 - like '%xx'
     2     select * from tb1 where name like '%cn';
     3 - 使用函数
     4     select * from tb1 where reverse(name) = 'wupeiqi';
     5 - or
     6     select * from tb1 where nid = 1 or email = 'seven@live.com';
     7     特别的:当or条件中有未建立索引的列才失效,以下会走索引
     8             select * from tb1 where nid = 1 or name = 'seven';
     9             select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
    10 - 类型不一致
    11     如果列是字符串类型,传入条件是必须用引号引起来,不然...
    12     select * from tb1 where name = 999;
    13 - !=
    14     select * from tb1 where name != 'alex'
    15     特别的:如果是主键,则还是会走索引
    16         select * from tb1 where nid != 123
    17 - >
    18     select * from tb1 where name > 'alex'
    19     特别的:如果是主键或索引是整数类型,则还是会走索引
    20         select * from tb1 where nid > 123
    21         select * from tb1 where num > 123
    22 - order by
    23     select email from tb1 order by name desc;
    24     当根据索引排序时候,选择的映射如果不是索引,则不走索引
    25     特别的:如果对主键排序,则还是走索引:
    26         select * from tb1 order by nid desc;
    27  
    28 - 组合索引最左前缀
    29     如果组合索引为:(name,email)
    30     name and email       -- 使用索引
    31     name                 -- 使用索引
    32     email                -- 不使用索引

    其他注意事项

    1 - 避免使用select *
    2 - count(1)或count(列) 代替 count(*)
    3 - 创建表时尽量时 char 代替 varchar
    4 - 表的字段顺序固定长度的字段优先
    5 - 组合索引代替多个单列索引(经常使用多个条件查询时)
    6 - 尽量使用短索引
    7 - 使用连接(JOIN)来代替子查询(Sub-Queries)
    8 - 连表时注意条件类型需一致
    9 - 索引散列值(重复少)不适合建索引,例:性别不适合

    limit分页

    无论是否有索引,limit分页是一个值得关注的问题

     1 每页显示10条:
     2 当前 118 120, 125
     3 
     4 倒序:
     5             大      小
     6    970  7 6  6 5  54  43  32
     7 19 98     
     8 下一页:
     9 
    10     select 
    11         * 
    12     from 
    13         tb1 
    14     where 
    15         nid < (select nid from (select nid from tb1 where nid < 当前页最小值 order by nid desc limit 每页数据 *【页码-当前页】) A order by A.nid asc limit 1)  
    16     order by 
    17         nid desc 
    18     limit 10;
    19 
    20 
    21 
    22     select 
    23         * 
    24     from 
    25         tb1 
    26     where 
    27         nid < (select nid from (select nid from tb1 where nid < 970  order by nid desc limit 40) A order by A.nid asc limit 1)  
    28     order by 
    29         nid desc 
    30     limit 10;
    31 
    32 
    33 上一页:
    34 
    35     select 
    36         * 
    37     from 
    38         tb1 
    39     where 
    40         nid < (select nid from (select nid from tb1 where nid > 当前页最大值 order by nid asc limit 每页数据 *【当前页-页码】) A order by A.nid asc limit 1)  
    41     order by 
    42         nid desc 
    43     limit 10;
    44 
    45 
    46     select 
    47         * 
    48     from 
    49         tb1 
    50     where 
    51         nid < (select nid from (select nid from tb1 where nid > 980 order by nid asc limit 20) A order by A.nid desc limit 1)  
    52     order by 
    53         nid desc 
    54     limit 10;
    View Code

    执行计划

    explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

    1 mysql> explain select * from tb2;
    2 +----+-------------+-------+------+---------------+------+---------+------+------+-------+
    3 | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
    4 +----+-------------+-------+------+---------------+------+---------+------+------+-------+
    5 |  1 | SIMPLE      | tb2   | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
    6 +----+-------------+-------+------+---------------+------+---------+------+------+-------+
    7 1 row in set (0.00 sec)
     1 id
     2         查询顺序标识
     3             如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;
     4             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
     5             | id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
     6             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
     7             |  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        |
     8             |  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |
     9             +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+
    10         特别的:如果使用union连接气值可能为null
    11 
    12 
    13     select_type
    14         查询类型
    15             SIMPLE          简单查询
    16             PRIMARY         最外层查询
    17             SUBQUERY        映射为子查询
    18             DERIVED         子查询
    19             UNION           联合
    20             UNION RESULT    使用联合的结果
    21             ...
    22     table
    23         正在访问的表名
    24 
    25 
    26     type
    27         查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
    28             ALL             全表扫描,对于数据表从头到尾找一遍
    29                             select * from tb1;
    30                             特别的:如果有limit限制,则找到之后就不在继续向下扫描
    31                                    select * from tb1 where email = 'seven@live.com'
    32                                    select * from tb1 where email = 'seven@live.com' limit 1;
    33                                    虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。
    34 
    35             INDEX           全索引扫描,对索引从头到尾找一遍
    36                             select nid from tb1;
    37 
    38             RANGE          对索引列进行范围查找
    39                             select *  from tb1 where name < 'alex';
    40                             PS:
    41                                 between and
    42                                 in
    43                                 >   >=  <   <=  操作
    44                                 注意:!= 和 > 符号
    45 
    46 
    47             INDEX_MERGE     合并索引,使用多个单列索引搜索
    48                             select *  from tb1 where name = 'alex' or nid in (11,22,33);
    49 
    50             REF             根据索引查找一个或多个值
    51                             select *  from tb1 where name = 'seven';
    52 
    53             EQ_REF          连接时使用primary key 或 unique类型
    54                             select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;
    55 
    56 
    57 
    58             CONST           常量
    59                             表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
    60                             select nid from tb1 where nid = 2 ;
    61 
    62             SYSTEM          系统
    63                             表仅有一行(=系统表)。这是const联接类型的一个特例。
    64                             select * from (select nid from tb1 where nid = 1) as A;
    65     possible_keys
    66         可能使用的索引
    67 
    68     key
    69         真实使用的
    70 
    71     key_len
    72         MySQL中使用索引字节长度
    73 
    74     rows
    75         mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值
    76 
    77     extra
    78         该列包含MySQL解决查询的详细信息
    79         “Using index”
    80             此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
    81         “Using where”
    82             这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
    83         “Using temporary”
    84             这意味着mysql在对查询结果排序时会使用一个临时表。
    85         “Using filesort”
    86             这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
    87         “Range checked for each record(index map: N)”
    88             这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。
    详细

    慢日志查询

    a、配置MySQL自动记录慢日志

    1 slow_query_log = OFF                            是否开启慢日志记录
    2 long_query_time = 2                              时间限制,超过此时间,则记录
    3 slow_query_log_file = /usr/slow.log        日志文件
    4 log_queries_not_using_indexes = OFF     为使用索引的搜索是否记录

    注:查看当前配置信息:
           show variables like '%query%'
         修改当前配置:
        set global 变量名 = 值

    b、查看MySQL慢日志

    mysqldumpslow -s at -a  /usr/local/var/mysql/MacBook-Pro-3-slow.log

     1 """
     2 --verbose    版本
     3 --debug      调试
     4 --help       帮助
     5  
     6 -v           版本
     7 -d           调试模式
     8 -s ORDER     排序方式
     9              what to sort by (al, at, ar, c, l, r, t), 'at' is default
    10               al: average lock time
    11               ar: average rows sent
    12               at: average query time
    13                c: count
    14                l: lock time
    15                r: rows sent
    16                t: query time
    17 -r           反转顺序,默认文件倒序拍。reverse the sort order (largest last instead of first)
    18 -t NUM       显示前N条just show the top n queries
    19 -a           不要将SQL中数字转换成N,字符串转换成S。don't abstract all numbers to N and strings to 'S'
    20 -n NUM       abstract numbers with at least n digits within names
    21 -g PATTERN   正则匹配;grep: only consider stmts that include this string
    22 -h HOSTNAME  mysql机器名或者IP;hostname of db server for *-slow.log filename (can be wildcard),
    23              default is '*', i.e. match all
    24 -i NAME      name of server instance (if using mysql.server startup script)
    25 -l           总时间中不减去锁定时间;don't subtract lock time from total time
    26 """
  • 相关阅读:
    网络流
    随机化
    sw抄来的主席树
    牛客SQL题解-统计各个部门的工资记录数
    牛客SQL题解-查找所有员工自入职以来的薪水涨幅情况
    牛客SQL题解-查找薪水排名第二多的员工编号emp_no、薪水salary、last_name以及first_name,不能使用order by完成
    牛客SQL题解-查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
    牛客SQL题解-获取薪水第二多的员工的emp_no以及其对应的薪水salary
    牛客SQL题解-统计出各个title类型对应的员工薪水对应的平均工资avg
    牛客SQL题解-查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
  • 原文地址:https://www.cnblogs.com/horror/p/9535648.html
Copyright © 2011-2022 走看看