MySQL索引和优化

MySQL逻辑分层

在这里插入图片描述

sql解析顺序

书写顺序

SELECT DISTINCT
    < select_list >
FROM
    < left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE
    < where_condition >
GROUP BY
    < group_by_list >
HAVING
    < having_condition >
ORDER BY
    < order_by_condition >
LIMIT < limit_number >

mysql解析器执行的顺序

 1 FROM <left_table>
 2 ON <join_condition>
 3 <join_type> JOIN <right_table>
 4 WHERE <where_condition>
 5 GROUP BY <group_by_list>
 6 HAVING <having_condition>
 7 SELECT 
 8 DISTINCT <select_list>
 9 ORDER BY <order_by_condition>
10 LIMIT <limit_number>

索引

问题:为什么千万条数据下加了索引依然很快?

答:mysql底层存索引的数据结构

  • 二叉树 如果索引是顺序的,二叉树就退化成了一个链表
    在这里插入图片描述

  • 红黑树 红黑树存在高度问题,如果高度是20,要查的索引在叶子节点,需要查20次
    在这里插入图片描述

  • Hash 对索引的key进行hash计算,算出存储位置,很多时候性能比B+树好,有hash冲突,不支持范围查询在这里插入图片描述

  • B树 B树的一个节点可以存放多个索引节点(数据+地址),索引数据是从左到右顺序递增
    叶子节点上和非叶子节点上的索引节点大概1KB的大小,索引每个节点能存16个索引节点
    假设这个B树有3层,能存放161616=4096,大概四千个索引节点,而且查找只需要3次
    在这里插入图片描述

  • B+树 B+树的索引数据都放在叶子节点上,非叶子节点只存放索引(冗余),不放数据
    假如给一个节点分配16KB的数据,非叶子节点上的一个索引节点(数据8B+地址6B)大约14B的大小,所以一个非叶子节点总共能存1170个索引节点
    叶子节点上的索引节点大概1KB的大小,所以一个叶子节点能放16个索引节点
    假设这个B+树有3层,能存放1170117016=21902400,大概两千万个索引节点,而且查找只需要3次
    在这里插入图片描述

B+树相比B树的优势:
  1.单一节点存储更多的元素,使得查询的IO次数更少;
  2.所有查询都要查找到叶子节点,查询性能稳定;
  3.所有叶子节点形成有序链表,便于范围查询。

存储引擎:

MyISAM:非聚集索引 索引和数据分开
每个MyISAM在磁盘上存储成三个文件
(1)frm文件:存储表的结构
(2)MYD文件:存放具体数据
(3)MYI文件:存储索引 索引放的是索引所在行的磁盘文件地址
在这里插入图片描述

InnoDB:聚集索引(聚簇索引) 索引和数据存在一起
每个InnoDB:在磁盘上存储成两个文件
(1)frm文件:存储表的结构
(2)ibd文件:存放索引所在行的其他列的数据
在这里插入图片描述

InnoDB的主键索引是聚集索引, 二级索引(非主键索引)的叶子节点放的是主键元素,然后去主键索引中拿到完整数据,也存在回表

为什么建议InnoDB必须建主键,并且推荐使用整型自增主键?

必须建主键?

mysql资源宝贵,自己能做的,不要麻烦数据库,影响性能
InnoDB底层必须要有个主键索引使用B+树维护数据,如果不建索引,mysql底层会在表中开始找
从最左边的列开始找,如果发现这一列的所有数据都不同,就会用这一列维护表的数据
如果一列都找不到,mysql会加一个隐藏列,用这个隐藏列维护表的数据

为什么使用整型?

查找索引时要进行比大小,整型比大小快

为什么要自增?

B+树的叶子节点要维护一个从左到右递增的顺序,
自增的话,一直会向后加,树节点进行分裂的概率很小
不是自增的话,有可能加到中间,数节点放满了就会进行分裂,而分裂非常耗费性能

优化

看执行计划,看是否合理的走了索引,然后看Extra,最好达到Using index,然后是type,最好达到ref

单表优化:
1.最佳左前缀,保证索引的定义和使用的顺序一致性
2.索引逐步优化
3.范围查询放在最后,防止索引失效

多表优化:
1.索引加在哪个表?
小表驱动大表,小表写在连接条件的左边,【对于左连接,给左表加索引,右连接,给右表加索引】
2.索引建立在经常查询的字段上

常用优化方法:

1.不要使用sleect *
2.exist和in

  • 如果主查询的数据集大,用in(外表大而内表小的情况)
  • 如果子查询的数据集大,用exist(外表小而内表大的情况)

3.order by
Using filesort有两种算法:单路排序、双路排序(根据IO次数)

  • MySQL4.1前,默认双路排序:扫描两次磁盘 1)从磁盘读取排序字段,对排序字段进行排序(在buffer中进行的排序) 2)扫描其他字段
  • MySQL4.1后,默认单路排序:只读取一次(全部字段),在buffer中进行排序,有隐患,不一定是真的单次,如果数据量特别大,无法将所有数据一次性读完,因此,会进行“分片读取、多次读取”
    单路排序使用时,根据数据量,可以调大buffer的大小:set max_length_for_sort_data = 1024 单位byte
  • 如果max_length_for_sort_data太小,则mysql会自动从单路->双路

1.选择单路、双路。调整buffer的大小
2.避免select *
3.复合索引不要跨列使用,避免Using filesort
4.保证排序字段的一致性(都升序或降序)

避免索引失效:

1.尽量使用索引覆盖
2.复合索引不要跨列或无序使用(最佳左前缀),尽量使用全索引匹配
3.不要在索引上进行任何操作(计算、函数、类型转换),否则索引失效
4.范围查询放在最后,否则范围查询后面的索引失效
5.复合索引不能使用不等于(!= <>)或 is null(is not null),否则自身以及右侧索引全部失效
6.like尽量以“常量”开头,不要以’%'开头,否则索引失效
7.字符串不加单引号(类型转换),索引失效
8.尽量不适用or,否则索引失效,用in代替
9.尽量避免子查询,而用join

SQL排查

慢查询日志:MySQL提供一种日志记录,用于记录MySQL中响应时间超阀值的SQL语句(long_query_time 默认10s)

相关参数:

  • slow_query_log :是否开启慢查询日志,1表示开启,0表示关闭。

  • log-slow-queries :旧版(5.6以下版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log

  • slow-query-log-file:新版(5.6及以上版本)MySQL数据库慢查询日志存储路径。可以不设置该参数,系统则会默认给一个缺省的文件host_name-slow.log

  • long_query_time :慢查询阈值,当查询时间多于设定的阈值时,记录日志。

  • log_queries_not_using_indexes:未使用索引的查询也被记录到慢查询日志中(可选项)。

  • log_output:日志存储方式。log_output=‘FILE’表示将日志存入文件,默认值是’FILE’。log_output='TABLE’表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log表中。MySQL数据库支持同时两种日志存储方式,配置的时候以逗号隔开即可,如:log_output=‘FILE,TABLE’。日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源,因此对于需要启用慢查询日志,又需要能够获得更高的系统性能,那么建议优先记录到文件。

日志分析工具mysqldumpslow

在实际生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,MySQL提供了日志分析工具mysqldumpslow

查看mysqldumpslow的帮助信息:

 1 [root@localhost~]# mysqldumpslow --help
 2 Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]
 3 
 4 Parse and summarize the MySQL slow query log. Options are
 5 
 6   --verbose    verbose
 7   --debug      debug
 8   --help       write this text to standard output
 9 
10   -v           verbose
11   -d           debug
12   -s ORDER     what to sort by (al, at, ar, c, l, r, t), 'at' is default
13                 al: average lock time
14                 ar: average rows sent
15                 at: average query time
16                  c: count
17                  l: lock time
18                  r: rows sent
19                  t: query time  
20   -r           reverse the sort order (largest last instead of first)
21   -t NUM       just show the top n queries
22   -a           do not abstract all numbers to N and strings to 'S'
23   -n NUM       abstract numbers with at least n digits within names
24   -g PATTERN   grep: only consider stmts that include this string
25   -h HOSTNAME  hostname of db server for *-slow.log filename (can be wildcard),
26                default is '*', i.e. match all
27   -i NAME      name of server instance (if using mysql.server startup script)
28   -l           don't subtract lock time from total time

例子:

-s, 是表示按照何种方式排序

    c: 访问计数
 
    l: 锁定时间

    r: 返回记录

    t: 查询时间
 
    al:平均锁定时间

    ar:平均返回记录数

    at:平均查询时间

-t, 是top n的意思,即为返回前面多少条的数据;

-g, 后边可以写一个正则匹配模式,大小写不敏感的;

 

比如:

得到返回记录集最多的10个SQL。

mysqldumpslow -s r -t 10 /database/mysql/mysql06_slow.log

得到访问次数最多的10个SQL

mysqldumpslow -s c -t 10 /database/mysql/mysql06_slow.log 

得到按照时间排序的前10条里面含有左连接的查询语句。

mysqldumpslow -s t -t 10 -g “left join” /database/mysql/mysql06_slow.log 

另外建议在使用这些命令时结合 | 和more 使用 ,否则有可能出现刷屏的情况。

mysqldumpslow -s r -t 20 /mysqldata/mysql/mysql06-slow.log | more
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值