MySQL---正确使用索引limit分页执行计划慢日志查询
Posted Horror
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 = ‘[email protected]‘;
7 特别的:当or条件中有未建立索引的列才失效,以下会走索引
8 select * from tb1 where nid = 1 or name = ‘seven‘;
9 select * from tb1 where nid = 1 or email = ‘[email protected]‘ 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;
执行计划
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 = ‘[email protected]‘
32 select * from tb1 where email = ‘[email protected]‘ 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 """
以上是关于MySQL---正确使用索引limit分页执行计划慢日志查询的主要内容,如果未能解决你的问题,请参考以下文章
坑,MySQL中 order by 与 limit 混用,分页有BUG!