1、如何判断索引是否优化,sql语句是否优化?
1.1 Explain是什么?有什么作用?(执行计划)
Explain是Mysql的关键字,显示mysql如何使用索引来处理select语句及连接表。可以帮助选择更好的索引和写出更优化的查询语句。使用Explain关键字可以模拟优化器执行语句,分析你的查询语句或是结构的性能瓶颈。在select语句之前加入explain关键字,MySQL会在查询上设置一个标记,执行查询会返回执行计划的信息,而不是执行这条SQL。
总之:explain用来查询sql语句是否被优化
explain关键字查询出来的列:
以下是需要关注的列,并优化相关语句:
select_type列
select_type列表示对应行是简单还是复杂的查询
- simple:简单查询,查询不包含子查询和union
- primary:复杂查询中最外层的select
- subquery:包含在select中的子查询(不在from子句中)
- derived:包含在from子句中的子查询,MySQL会将结果存放在一个临时表中,也称为派生表
type列
这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据行记录的大概范围。依次从最优到最差分别为:
system > const > eq_ref > ref > range > index > ALL
一般来说,得保证查询达到range级别,最好达到ref NULLibie:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。
例如:在索引列中取最小值,可以单独查找索引来完成,不需要在执行时访问表。
mysql> explain select min(id) from film;
const、system:mysql能对查询的某部分进行优化并将其转化为一个常量(可以看show warnings的结果)。用于primary key或unique key的所有列与常数比较时,所有表最多有一个匹配行,读取1次,速度比较快。system是const的特例,表里只有一条元组匹配时为system
1.2 如何判断是否优化成功
1.可以通过执行计划显示的数据判断査询语句是否使用了索引。 索引类型:检查执行计划中的"possible keys"和"key"列,确认査询是否使用了正确的索引。如果没有使用到任何索引,则说明 SQL语句没有被优化。
2.可以査看到索引优化前后type 的值来判断是否优化了,还可以判断sql 调优是否真正的被调优成功。
**3.执行行数:**执行计划中的"rows"列显示了 MySQL估算需要扫描的行数。如果这个数字太大,那么可能需要修改查询语句或者添加索引来改善性能。
****对于执行计划 explain,参数有:
- possible keys 字段表示可能用到的索引;
- key 字段表示实际用的索引,如果这一项为 NULL,说明没有使用索引;
- key_len 表示索引的长度:
- rows 表示扫描的数据行数。
- type 表示数据扫描类型,我们需要重点看这个。
****对于type 字段的值有:
type字段就是描述了找到所需数据时使用的扫描方式是什么,常见扫描类型的执行效率从低到高的顺序为:
- ALL(全表扫描)
- index(全索引扫描)
- range(索引范围扫描)
- ref(非唯一索引扫描)
- eq_ref(唯一索引扫描);
- const(结果只有一条的主键或唯一索引扫描)最最最优
4.考虑到査询效率问题,要尽量避免全表扫描和全索引扫描,也要避免 extra 的结果为using filesort 的语句。
**5.排序类型:**如果执行计划中需要进行排序,那么可以考虑添加一个排序索引或者调整查询语句的顺序,以避免进行额外的排序操作。
**6.查询类型:**如果执行计划中出现了 FULL TABLESCAN,即全表扫描,则说明没有使用到任何索引,查询效率不高。在这种情况下,可以考虑添加索引或者优化查询语句。
2、索引
2.1 索引概念
索引是 SQLServer 编排数据的内部方法,是检索表中数据的直接通道。它类似汉语词典里面的拼音目录,通过它可以快速查找到某个字词。
索引页是数据库中存储索引的数据页。索引页存放检索数据行的关键字页 及数据行的地址指针 。索引页类似于汉语字典中按拼音或笔画排序的目录页。
- 索引页 ----->目录页(把拼音和笔画写到目录里面,在 mysql中就是一行索引的数据放到索引页里面,如果要去查询某一行,就来索引页里面匹配)
- 关键字 ----->按拼音或笔画排序
- 地址指针------>在哪一页(第几页)
索引页:包括关键字和地址指针
索引优点:使用索引查找数据,无需对整表进行扫描,可以快速找到所需数据
2.2 索引分类
1、唯一索引(id):
是指对一个表中的某个列创建索引,并且要求该列中的所有数据都是唯一的,也就是不能有重复的值。唯一索引可以提高查询效率、确保数据完整性,并防止重复的数据被插入到数据库中。(可有多个)
创建一个唯一索引:
CREATE UNIQUE INDEX index id ON student (id);
或者alter table student add unique (id);
怎么使用唯一索引:
select * from student where id=1:
在实践中,唯一索引经常用于限制表中某一列的取值必须唯一。例如,在一个用户表中建立唯一索引可以防止多个用户使用相同的电子邮件地址注册帐户。当您尝试插入一个重复的记录时,数据库会返回错误,因为唯一索引的限制条件不允许该列中有重复的值。
2. 主键索引:
是唯一索引的一种特殊类型。创建主键会自动创建主键索引。要求主键中的每个值是非空,唯一的。(主动对主键建立 B+树索引,以便快速定位和查找)
CREATE TABLE mytable (
id INT NOT NULL AUTO INCREMENT,
name VARCHAR(50),
age INT,
PRIMARY KEY (id)
);
创建一个主键索引,一般是在创建表的时候创建主键索引
ALTER TABLE student ADD PRIMARY KEY (id);
3.聚簇索引(聚集索引):
按照索引的键值对表进行重排,使得数据的物理存储顺序和索引顺序一致。因此每个表只能有一个聚簇索引,且聚簇索引的键值不能包含空值。(一表只能有一个)
它是一种特殊的索引方式,是主键索引的一种形式 ;它会按照主键值的大小来组织表中的数据。简单来说,聚簇索引就是将数据按照主键值 进行排序,形成一个有序的数据结构这个有序的数据结构就是聚簇索引。在 MySQL 中使用 InnoDB 引擎创建的表默认都使用聚簇索引。
聚簇索引通常用于经常需要按照主键或某些范围査询来访问数据的表,它可以提高査询效率并且在处理大量数据时也比较快速。
创建一个聚簇索引:(创建主键索引时,会自动创建一个聚索引)ALTER TABLE student ADD PRIMMARY KEY (id);
4、非聚簇索引:
表中各行数据存放的物理顺序与键值的逻辑顺序不匹配,索引和表格数据分开存放,索引内存储的是指向对应数据所在位置的指针或行标识。聚簇索引比非聚簇索引有更快的数据访问速度。(可以有多个)(说个大白话:非聚就是"普通索引")
与聚簇索引不同,非聚簇索引并不会对表中的数据进行重排,而是单独建立一个索引对象,用来存储指向表中数据行的指针或者物理地址。当查询操作需要使用到该索引时,数据库会先根据索引找到对应的行记录,再通过行记录的指针或者物理地址查找到对应的数据。
相比于聚簇索引,非聚簇索引可以提高非主键列的查询和更新效率,但是却无法提高主键査询和聚簇索引范围査询的效率。在 MySQL 中,在使用InnoDB 存储引擎时,除了主键索引都是非聚簇索引。
CREATE INDEX id name ON student (name); 这里不是创建的主键索引(id),那么这里的 name 就是非聚簇索引。
ALTER TABLE student ADD INDEX id name (name);
***如果已经创建好了表,然后再创建一个非聚索引,就用这样的语句***
一般来说id 列用来创建唯一索引,主键索引,聚簇;非id 一般用来创建非聚簇索引。
5、复合索引(联合索引,组合索引):将多个列的组合作为索引(一表中可多个)
创建一个复合索引:
CREATE INDEX name score ON student (name, score);
如何使用复合索引:
SELECT* FROM student WHERE name='赵六'AND score=78;
如果搜索条件只写一个 score 条件,那么将无法使用复合索引
6、全文索引(见下文):
是一种特殊类型的寄语标记的功能型索引,由SQLserver 中全文引擎服务创建和维护。(一表中可多个)
总结:主键索引和聚簇索引的区别:
- 1、主键索引更注重在主键列上的査询效率,而聚簇索引更注重整个表格上的查询效率
- 2、主键对少量数据行操作,聚簇适用快速扫描所有行的数据
- 3、主键要求列里面唯一性,聚簇索引不一定要求列里面数据唯一性
看起来聚族索引的好处更广(在 mysql5.5 以后聚族索引就是主键索引)
2.3 创建索引
2.3.1创建一个 B+tree 的索引(底层数据结构是 B+ 树)
给 name 创建一个 B+tree 索引
create index id_name on student (name);
给 name,age 创建一个联合索引
create index id_name_age on student(name, age);
2.3.2创建一个 hash 索引(底层数据结构是 hash表)
哈希索引适用于等值筛选场景,可以加快等值查询的速度。
CREATE INDEX id_name ON student (name) USING HASH:
(在其他存储引擎才支持 hash)
Mysql 中默认是 b+tree 索引,因为用的 InnoDB 存储引擎,不支持 hash 索引。
**缺点:**只支持等值查询,空间利用不够高效,对内存要求较高,如果内存不足,可能会崩溃
3.3.3创建一个全文索引(底层数据结构是字典树)
全文索引适用于关键字搜索场景,可用于加快包含大量文本数据的表的查询速度,比如文章中的某个名词。
CREATE FULLTEXT INDEX id content ON article (content);
缺点: 仅支持英文和数字,其他语言要用插件,mysql5.5 以上版本已被弃用,长度最大为4个字符的单词。
使用场景:SELECT * FROM artice WHERE MATCH (content) AGAINST ('SQL');
***该査询语句将匹配 content 字段中包含关键字"SQL"的文章,并将结果返回。***
2.4 查看索引
2.4.1 使用 DESCRIBE 语句
DESCRIBE 语句可以查看表结构和索引信息,其中,Key列表示该字段对应的索引类型,包括PRIMARY(主键索引)、UNIQUE(唯一索引)、FULLTEXT(全文索引)和普通索引等。如果该字段未被索引,则该列值为 NULL。
使用:DESCRIBE mytable;
2.4.2 使用 SHOW INDEX语句可以查看表的索引信息
内容包括索引名称、字段名、索引类型、索引方法、索引列长度等参数,用于帮助我们更好地理解索引的构成和使用情况
便用:SHOW INDEX FROM student;
2.5.删除案引
DROP INDEX id_name ON student;
注意:id name 是索引名,而不是表字段名。删除之前也要确定不再使用,否则会导致性能
下降。
2.6 注意事项
针对以下情况创建索引:
- 频繁搜索的列
- 经常用作查询选择的列
- 经常排序、分组的列
- 经常用作连接的列(主外键)
针对以下情况不创建索引:
- 仅包含几个不同值的列表中
- 仅包含几行数据
经验:
- 查询是尽量少用"*"返回全部列,不要返回不需要的列
- 索引尽量在字节数少的列上建立
- 索引where 字句中有多个表达式时,包含案引列的表达式应置于其他表达式之前避免在 order by 子句中使用表达式(算术运算符,条件表达式,between and,in,like,isnull,and ,or
- 根据业务数据发生频繁,定期重新生成或重新组织索引,进行碎片整理
3、sql调优方法
sql调优的几种方式:避免使用 select *、用 union all 代替 union、小表驱动大表、批量操作、多用 1imit、in 中值太多、增量査询、高效的分页、用连接查询代替子査询、join 数量不宜过多、join 时需要注意、控制索引的数量、选择合理的字段类型、提升 group by 的效率、索引优化。
4、慢查询
MySQL的慢查询是指执行时间超过一定阈值的查询语句。慢查询可能导致数据库性能下降,影响应用程序的响应时间。这个阈值可以根据具体的业务需求和系统性能来设置。一般来说,执行时间超过几百毫秒或几秒钟的查询语句可以被认为是慢查询。
4.1 导致慢查询的因素与解决方法
1、索引问题
查询语句没有使用适当的索引,导致数据库需要全表扫描来查找匹配的数据,从而增加查询时间。优化方法:建立索引,并使用索引,还可以对索引进行优化,让其更加高效。
2、数据库结构设计问题
表的设计不合理,导致查询需要多次关联、子查询或者复杂的计算,从而增加查询时间。
优化方法:实际就是把慢查询的产生原因解决了,查询和关联导致时间慢,那就把这些操作预先解决掉,提供给用户直接查询,那就不会慢了。
3、数据库参数配置问题
MySQL 的一些参数配置不合理,如缓冲区大小、连接数限制等,可能导致慢查询。举个真实案例说明一下:某公司的订单数据库中包含了几十亿条订单记录,由于查询频繁且数据量庞大,导致查询速度较慢,无法满足业务需求如何优化呢?
- 1、查看数据库当前参数配置SHOW VARIABLES LIKE'max connections;最大连接数SHOW VARIABLES LIKE 'innodb buffer_pool size';缓冲区大小SHOW VARIABLES LIKE 'innodb log file size;日志文件大小
- 2、优化 max connections 参数:根据业务负载情况和硬件资源,适当调整max connections 参数,限制并发连接数,避免资源过度竞争。例如,将其从默认值设置为合理的值如 1000,如果设置太大,会导致性能比较差
SET GLOBAL max connections=1000;
- 3、调整 innodb buffer pool size 参数:将 innodb buffer pool size 参数设置为适当的值,以提高数据缓存区域的大小,减少磁盘读取次数。根据服务器内存情况,将其设置为较大的值,比如 70-80% 的可用内存,32GB的百分之七八十
- 4、调整 innodb log file size 参数:根据当前的日志文件大小,评估是否需要增加其大小来减少频繁的刷新操作。一般建议将 innodb log file size 设置为 1GB 或更大。
- 5、分区表:考虑将订单表进行分区,根据时间范围或其他字段进行分区,将大表分割成多个较小的子表,以减少查询范围,提高查询性能。
- 6、数据库垂直拆分和水平拆分:如果业务需要,可以考虑对数据库进行垂直拆分或水平拆分,将不同的业务模块或数据拆分到不同的数据库或表中,以减少单个表的数据量,提高查询效率。
4、查询语句写法问题
查询语句的编写不合理,可能存在多余的操作、不必要的排序或者条件判断等,导致查询效率低下存在慢査询的 sql 语句问题:
SELECT COUNT(*)AS order count, SUM(amount) AS total amount
FROM orders
WHERE customer id='12345'GROUP BY customer id;
优化后:
SELECT COUNT(*)AS order count, SUM(amount) As total amount
FROM orders
WHERE customer id='12345';
由于是一个明确的客户,是不需要 groupby的,所以这里使用了,反而会影响效率,
4.2 优化数据库的其他方法
1、使用缓存
对于一些静态数据或者结果集,可以使用缓存来加速查询,减少对数据库的访问。用redis 来缓存静态数据,热门数据,以及经常被查询的数据
2、数据对象缓存
使用 Hibernate 的二级缓存、Spring Boot 的缓存注解等,将数据库中的数据对象(如实体对象)进行缓存,以减少对数据库的频繁读取。
3、监控和日志分析
通过 MySQL提供的慢查询日志或者其他性能监控工具(Percona Monitoring andManagement),对慢查询进行监控和分析,找出潜在的问题,并进行相应的调整。使用慢查询日志进行分析慢查询语句:
- 1、启用慢査询日志:首先,需要在 MySQL配置文件中启用慢查询日志功能。找到并修改配置文件(通常是 my.cnf 或 my.ini),添加以下配置项:
slow query log=1
slow query log file=/路径/slow-query.log
long query time=1
long_query_time 参数定义了査询执行时间超过多少秒才被记录为慢查询,默认为 10秒。
- 2、收集慢査询日志:重启 MVSQL服务后,系统会开始记录慢査询日志。让其运行一段时间(例如几个小时或一天),以便收集足够的查询数据
- 3、分析慢査询日志:使用工具(如mysqldumpslow)来分析慢查询日志文件,找出执行时间较长的查询语句:mysqldumpslow/路径/slow-query.log
- 这将列出执行时间最长的查询语句及其执行次数等信息
- 4、优化慢査询(上述多种方法优化)
- 5、测试和验证:对优化后的查询语句进行测试,确保其性能得到明显的改善。可以使用 EXPLAIN 命令来查看查询执行计划,评估优化效果
- 6、后续继续监控和持续优化