MySQL---正确使用索引、limit分页、执行计划、慢日志查询
程序员文章站
2022-10-03 22:34:46
正确使用索引 数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。即使建立索引,索引也不会生效: 其他注意事项 limit分页 无论是否有索引,limit分页是一个值得关注的问题 1 每页显示10条: 2 当前 118 120, ......
正确使用索引
数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。
即使建立索引,索引也不会生效:
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;
执行计划
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 """