首页 > 数据库 >MySQL 优化

MySQL 优化

时间:2023-06-18 19:35:10浏览次数:54  
标签:WHERE 查询 索引 key MySQL table 优化 SELECT

SQL 优化是提高 MySQL 数据库性能和查询效率的过程。下面是一些常见的 SQL 优化技巧:

  1. 优化表结构:合理的表结构设计有助于提高性能。特别是,列是否具有正确的数据类型,每个表是否具有符合业务需求的列?例如,执行频繁更新的业务通常表比较多,列很少,而分析大量数据的业务通常表比较少,列很多。
  2. 编写高效的查询:编写高效的 SQL 是优化查询性能的关键。避免使用不必要的 SELECT * 查询,只选择需要的列。合理使用 WHEREJOINGROUP BYORDER BY 等子句,以尽量减少数据库的负担。
  3. 适当的冗余字段:冗余字段可以提高查询性能,但必须考虑数据一致。冗余字段应遵循:不是频繁修改的字段;不是唯一索引的字段;不是 varchar 超长字段,更不能是 text 字段。这种方式也被称作反范式。
  4. 使用合适的索引:索引是提高查询效率的关键。确保表中的字段经常用于搜索并在这些列上创建索引。特别是,在使用外键进行连表查询时,索引尤其重要。
  5. 避免全表扫描:全表扫描会对性能产生严重影响,特别是对大表来说。尽量避免在查询中使用不带索引的列,以免触发全表扫描。
  6. 使用 EXPLAIN 分析查询计划:MySQL 提供了 EXPLAIN 关键字,可以帮助分析查询语句的执行计划。通过查看执行计划,可以了解查询是如何使用索引和执行的顺序,从而找出可能存在的性能问题。
  7. 分析慢查询:通过 MySQL 的慢查询日志或者其他监控工具,找出执行时间较长的 SQL 查询语句。分析这些慢查询的执行计划、索引使用情况等信息,确定可能存在的性能问题。
  8. 缓存重复查询结果:对于一些相对静态的查询结果,可以考虑使用缓存技术,如 Redis,将查询结果缓存起来,减少数据库的访问次数。

使用合适的索引

提高 SELECT 子句的查询性能的最佳方式是在一个或多个列上创建索引。索引就像是指向表行的指针,使查询可以快速确定哪些行匹配 WHERE 子句中的查询条件,并检索这些行的其他列值。

但是,需要注意的是,不必要的索引反而会降低性能。索引增加了插入、更新和删除的成本,因为每个索引都必须更新。必须找到正确的平衡点,以使用最佳的索引集实现快速查询。

索引的创建应遵循以下原则:

  • 因为每个 InnoDB 表都有一个主键(不管你是否主动创建它),所以要为每个表指定一组主键列,这些列用于最重要和最关键的查询。

  • 不要指定太多或太长的列为主键,因为这些列值在每个辅助索引中都是重复的。当索引包含不必要的数据时,读取这些数据的 I/O 和缓存这些数据的内存会降低服务器的性能和可伸缩性。

  • 不要为每个列创建单独的二级索引而应该创建联合索引,因为每个查询只能使用一个索引。在很少使用的列或只有少数不同值的列上建立索引可能对查询都没有任何帮助。而对于联合索引,如果索引包含结果集所需的所有列(称为覆盖索引),则查询可能完全能够避免读取表数据。

  • 只有经常作为查询条件的列才需要创建索引,如果在在查询条件中很少使用的列创建了索引,反而会降低性能,索引增加了插入、更新和删除的成本,因为每个索引都必须更新。

  • 在用于连接(JOIN)的列上创建索引,这些列主要是外键,可以加快连表查询的速度。

  • 在需要根据范围(<,<=,=,>,>=,BETWEEN,IN)进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的。

  • 在需要排序(order by)的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间。

  • 对于数据量很少或者重复值多的列不应该创建索引。

  • 对于 text, image 和 bit 数据类型的列不应该创建索引。

更多规范可以参考阿里巴巴 Java 开发手册

索引失效场景

  1. 最左前缀原则:

    如果在(col1, col2, col3)上有一个三列索引,则在(col1)、(col1, col2)和(col1, col2, col3)能命中索引。

    如果列没有在索引的最左边形成前缀,MySQL 就不能命中索引。假设你有如下所示的 SELECT 语句:

    SELECT * FROM tbl_name WHERE col1=val1;
    SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
    
    SELECT * FROM tbl_name WHERE col2=val2;
    SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;
    

    如果在(col1, col2, col3)上存在索引,则只有前两个查询能命中该索引。第三和第四个查询确实涉及到了索引列,但不能命中索引,因为(col2)和(col2, col3)不是(col1, col2, col3)的最左前缀。

  2. 条件中含有计算、函数、类型转换:

    以下语句都会使索引失效:

    SELECT * FROM tbl_name WHERE age + 1 ='1';
    SELECT * FROM tbl_name WHERE date(create_time)='20190101';
    SELECT * FROM tbl_name WHERE col1='1';    -- col1 为 int 类型
    
  3. Like 以 % 开头:

    使用双 % 号的查询条件。如:col1 like '%123%',会是索引失效,为使索引生效,可以只添加后置 %,如:a like '123%'

  4. 范围查询右侧的索引失效:

    如果在(col1, col2, col3)上有一个三列索引,并进行了以下查询:col1 > 5 AND col2 = 1 AND col3 = 4,这种情况下,虽然 col1 可以命中缓存,但是 col2 和 col3 缓存会失效。如果要让所有缓存生效,可以将需要进行范围查找的列放在联合索引的右侧。

  5. NOT IN 使索引失效:

    NOT IN 通常会使索引失效,使用 NOT EXISTS 来替换 NOT IN。

查询执行计划

在执行查询之前,MySQL 优化器会选择执行最有效查询的操作集,这称为“查询执行计划”,也称为 EXPLAIN 计划。我们的目标是识别 EXPLAIN 计划中表明查询优化得很好的方面,并学习 SQL 语法和索引技术,以便在遇到一些低效操作时改进计划。

EXPLAIN 语句提供了 MySQL 如何执行语句的信息。在 EXPLAIN 的帮助下,我们可以看到应该在哪里向表添加索引,以便通过使用索引查找行来加快语句的执行速度。

EXPLAIN 可以与 SELECT, DELETE, INSERT, REPLACE 和 UPDATE语句一起工作。

EXPLAIN 输出格式

EXPLAIN 的每个输出行提供关于一个表的信息:

描述
id SELECT 标识符
select_type SELECT 类型
table 输出行的表名
partitions 匹配的分区
type 连接类型
possible_keys 可供选择的索引
key 实际使用的索引
key_len 所使用的索引的长度
ref 列与索引的比较
rows 预计要检索的行数
filtered 按条件过滤的行百分比
Extra 附加信息

id

SELECT 的序号,用来标识整个查询中 SELELCT 语句的序号。

select_type

SELECT 的 类型,可以是下表中所示的类型。

描述
SIMPLE 简单的 SELECT (不使用 UNION 或子查询)
PRIMARY 查询中如果包含子查询,外层的查询的 SELECT。
UNION UNION 中的第二个或之后的 SELECT 语句
UNION RESULT UNION的结果。
SUBQUERY 子查询中的第一个 SELECT
DERIVED 派生表,比如在 FROM 中出现的子查询

table

查询用到的表名,每行都有对应的表名,表名除了正常的表之外,也可能是以下列出的值:

  • <unionM,N> : id 值为 M 和 N 的行的并集。
  • <derivedN> : 该行引用 id 值为 N 的行的派生表结果,例如,派生表可能来自 FROM 子句中的子查询。

type

连接类型。性能从最优到最差排序:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL。

  • const:表中最多只有一行匹配的记录,当使用主键或唯一索引的字段作为查询条件时 type 为 const:

    SELECT * FROM tbl_name WHERE primary_key=1;
    
    SELECT * FROM tbl_name
      WHERE primary_key_part1=1 AND primary_key_part2=2;
    
  • eq_ref:当连表查询时,前一张表的行在当前这张表中只有一行与之对应。除了 system 和 const 类型之外,这是最好的连接类型。当使用主键或唯一索引的字段作为连表条件时 type 为 eq_ref。

    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column=other_table.column;
    
    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column_part1=other_table.column
      AND ref_table.key_column_part2=1;
    
  • ref:使用普通索引作为查询条件,查询结果可能找到多个符合条件的行。

    SELECT * FROM ref_table WHERE key_column=expr;
    
    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column=other_table.column;
    
    SELECT * FROM ref_table,other_table
      WHERE ref_table.key_column_part1=other_table.column
      AND ref_table.key_column_part2=1;
    
  • ref_or_null:这种连接类型类似于ref,但是MySQL会对包含NULL值的行进行额外的搜索。这种连接类型优化最常用于解析子查询。

    SELECT * FROM ref_table
      WHERE key_column=expr OR key_column IS NULL;
    
  • index_merge:当查询条件使用了多个索引时,表示开启了 Index Merge 优化,此时执行计划中的 key 列列出了使用到的索引。

  • range:对索引列进行范围查询,执行计划中的 key 列表示哪个索引被使用了。

    SELECT * FROM tbl_name
      WHERE key_column = 10;
    
    SELECT * FROM tbl_name
      WHERE key_column BETWEEN 10 and 20;
    
    SELECT * FROM tbl_name
      WHERE key_column IN (10,20,30);
    
    SELECT * FROM tbl_name
      WHERE key_part1 = 10 AND key_part2 IN (10,20,30);
    
  • index:除了扫描索引树之外,索引连接类型与ALL相同。如果是覆盖索引,则只扫描索引树。仅索引扫描通常比 ALL 更快,因为索引的大小通常小于表数据的大小。

  • ALL:全表扫描。

possible_keys

表示 MySQL 执行查询时可能会用到的索引。如果该列为 NULL,则没有相关索引。在这种情况下,你应该检查 WHERE 子句来检查它是否引用了适合建立索引的列,从而提高查询的性能。如果是,则创建一个适当的索引,并再次使用EXPLAIN检查查询。

key

表示 MySQL 实际使用到的索引。要强制 MySQL 使用或忽略在 possible_keys 列中列出的索引,可以在查询中使用 FORCE INDEX, USE INDEX, 或者 IGNORE INDEX

key_len

key_len 列表示 MySQL 实际使用的索引的最大长度;当使用到联合索引时,有可能是多个列的长度和。

rows

rows 列表示根据表统计信息及选用情况,大致估算出执行查询要检查的行数。对于 InnoDB 表,这个数字是一个估计值,可能并不总是准确的。

Extra

关于 MySQL 如何解析查询的附加信息。通过这些信息,可以更准确的理解 MySQL 是如何执行查询的。常见的值如下:

  • const row not found:对于SELECT…FROM tbl_name,表为空。

  • Using index:表明查询使用了覆盖索引,不用回表,查询效率非常高。

  • Using where:表明查询使用了 WHERE 子句进行条件过滤。一般在没有使用到索引的时候会出现。

  • Using filesort:在排序时使用了外部的索引排序,没有用到表内索引进行排序。

  • Using temporary:为了解析这个查询,MySQL需要创建一个临时表来保存结果。常见于 GROUP BY 和 ORDER BY 子句。

  • Using index condition:表示查询优化器选择使用了索引条件下推这个特性。

基于 Spring Boot 2.7.12、MyBatis-Plus、Spring Security 等主流技术栈构建的后台管理系统。
后台:https://gitee.com/linjiabin100/pi-admin.git
前端:https://gitee.com/linjiabin100/pi-admin-web.git

标签:WHERE,查询,索引,key,MySQL,table,优化,SELECT
From: https://www.cnblogs.com/zn-pi/p/17489614.html

相关文章

  • 2023.6.18 12.数据库配置优化
    12.数据库配置优化mysql数据库优化框架体系优化要有框架和体系:根据⽤户访问⽹站流程优化集群,根据OSI7层模型,从下往上优化数据库!1、硬件层⾯优化1.1数据库物理机采购:1.2服务器硬件配置调整1.2.1服务器BIOS调整1.2.2阵列卡调整2、软件层优化2.1操作系统层⾯优化2.1.1操......
  • 机器学习算法的实现与优化
    目录1.引言2.技术原理及概念3.实现步骤与流程4.应用示例与代码实现讲解5.优化与改进6.结论与展望7.附录:常见问题与解答人工智能专家,程序员,软件架构师,CTO,以下是《48.机器学习算法的实现与优化》技术博客文章的文章结构:1.引言1.1.背景介绍机器学习技术的发展历程机......
  • 强化学习中的模型调优与优化
    目录《强化学习中的模型调优与优化》引言强化学习是一种机器学习领域的重要分支,旨在让智能体通过与环境的交互来学习最佳行为策略,从而完成目标任务。在强化学习中,模型作为智能体的决策引擎,必须能够高效地执行搜索策略,以最大化奖励函数的期望值。然而,在实际训练和调优中,模型可能......
  • MySQL数据库主从搭建(详细图文)
    文章目录前言一、主从搭建准备二、Master1.修改mysql配置文件2.创建授权用户3.查看日志和宿主机master的状态三、slave操作1.修改宿主机的server-id2.进入mysql执行相关命令3.UUID的相关配置四、测试前言主从原理:MySQL之间数据复制的基础是二进制日志文......
  • mysql记录多行结果的小实验
    通过#保存多个记录,比如,下线开始时间#下线多少天,下线结束时间如果想要做数据计算可以通过SUBSTRING_INDEX(offline_record,'#',3)拿到对应的结果。比如我要对比获取第三个的所有数据,现在时间是2023-06-1814:20:21超过这个时间的就要离线了。我要查询到所有的数据。SELECT*......
  • Linux安装mysql登录问题-适用root强制登录
    安装mysql后,常规方法登录出现错误提示。直接:/etc/my.cnf添加以下加粗的三句:#cacheinMySQL.Startat70%oftotalRAMfordedicatedserver,else10%.#innodb_buffer_pool_size=128M##Removeleading#toturnonaveryimportantdataintegrityoption:loggi......
  • mysql -- 根据变量a的不同值设置变量b(case when + set)
    需求:根据变量 @period_endtime的不同值,设置相对应的@end_type@period_endtime@end_type03311063020930312314 实现:set@i_period='20230331';SET@period_endtime=RIGHT(@i_period,4);SET@end_type=CASE@period_endtime......
  • 基于Eclipse+MySQL+J2EE开发的天猫商城
    基于Eclipse+MySQL+J2EE开发的天猫商城项目介绍......
  • mysql:报错Incorrect string value:’\xF0\x9F\x94\xA6\xF0\x9F…’
     一,报错信息:1,报错:Incorrectstringvalue:'\xF0\x9F\x94\xA6\xF0\x9F...'forcolumn'content'atrow1报错的原因:字符串中包含了emoji表情:如:......
  • MySQL数据库页存储结构学习与了解
    MySQL数据库页存储结构学习与了解背景MySQL总是出现奇奇怪怪的问题.想着自己能够学习与提高一下.最近看了很多文档.关于MySQL数据库相关的.想着总结和提炼一下,希望能够给未来的工作提供一下指导.MySQL的存储引擎MySQL有多种存储引擎,主要有:InnoDB:是MySQL的默认存储引擎。......