
华为一面:说说看MySQL的索引类型及其作用?什么是聚簇索引和非聚簇索引?索引失效的情况有哪些?说说看回表、覆盖索引和索引下推?
面试题概览:
-
说说看MySQL的索引类型及其作用?
-
能说说看Innodb的B-Tree索引的结构和索引的过程?
-
什么是聚簇索引和非聚簇索引?他们的区别是什么?
-
能说说回表的概念,回表的过程是怎么样的?
-
什么是覆盖索引和索引下推,说说看他们解决了什么问题?能给出使用到了覆盖索引和索引下推的具体例子吗?
-
联合索引(组合索引/复合索引)是什么?使用时有什么注意事项?
-
说说看索引失效的情况有哪些?如果我对”性别“字段建立索引能有效使用索引吗?
-
如果线上存在慢sql,该怎么排查和优化?
面试官:说说看MySQL的索引类型及其作用
以下是MySQL中常见的索引类型及其作用的详细介绍:
一、常见索引类型
- B-Tree索引
* 作用 :B-Tree索引是MySQL中最常用的索引类型,它支持全值匹配、范围查询和前缀匹配,适用于大多数查询操作。
* 特点 :B-Tree索引基于树形数据结构,表中的每一行都会在索引上有一个对应值。查询时,可以根据索引值一步一步定位到数据所在的行。
- 哈希索引
* 作用 :哈希索引基于哈希表实现,它支持全值匹配查询,但不支持范围查询和前缀匹配。
* 特点 :哈希索引通过计算索引列的哈希值来定位数据行。在MySQL中,哈希索引主要应用于MEMORY存储引擎。需要注意的是,由于哈希计算比较耗时,建立哈希索引会比B-Tree索引耗费更多的时间。
- 全文索引
* 作用 :全文索引主要用于对文本字段进行全文搜索,它基于倒排索引实现。
* 特点 :全文索引可以在CHAR、VARCHAR和TEXT列上创建,适用于包含大量文本数据的列,如文章内容、评论等。在MySQL中,全文索引主要应用于MyISAM和InnoDB存储引擎。但需要注意的是,全文索引在插入和更新数据时的性能开销较大。
- 空间索引
* 作用 :空间索引用于地理空间数据类型的查询,它基于R树实现。
* 特点 :空间索引主要用于GIS(地理信息系统)应用,支持对空间数据类型(如POINT、LINESTRING、POLYGON)进行快速查询。在MySQL中,空间索引主要应用于MyISAM和InnoDB存储引擎。但需要注意的是,空间索引只适用于特定的存储引擎。
- 主键索引
* 作用 :主键索引是一种特殊的唯一索引,用于确保每行数据的唯一性。
* 特点 :主键索引不允许NULL值,一个表只能有一个主键索引。它通常用于表的标识符字段,并自动创建索引。在选择主键索引时,应尽量选择单一列且较短的字段,以提高检索效率。主键值不宜频繁更新,因为这会影响索引的重建。
- 唯一索引
* 作用 :唯一索引用于确保列的值是唯一的,但允许NULL值。
* 特点 :一个表可以有多个唯一索引。唯一索引强制列值的唯一性,防止重复数据。可以在多个列上创建唯一索引。
- 普通索引
* 作用 :普通索引适用于查询频繁但没有唯一性要求的列。
* 特点 :普通索引的列值可以重复且允许NULL值。它是最基本的索引类型,没有唯一性约束。可以在表的一个或多个列上创建。普通索引可以提高查询速度,但没有唯一性要求。
- 组合索引
* 作用 :组合索引是在多个列上创建的索引,用于提高多列组合查询的性能。
* 特点 :组合索引可以包含多个列,通常用于联合查询。它遵循最左前缀原则,即查询条件必须包含最左边的列。组合索引的列顺序应根据查询频率和过滤条件进行设计。
二、索引的作用
-
提高查询性能 :索引可以显著减少数据库查询时需要扫描的行数,通过直接访问索引来快速定位所需数据,从而加快查询速度。
-
加速排序和分组 :索引可以帮助加速ORDER BY和GROUP BY操作,减少排序和分组的时间消耗,因为索引本身就对数据排好了序。
-
加速连接操作 :当进行连接查询时,索引可以帮助优化连接操作的效率,减少连接操作的时间。
-
提高数据唯一性和完整性 :通过在列上创建唯一索引或主键索引,可以确保数据的唯一性和完整性,避免重复数据或无效数据的存在。
三、注意事项
-
选择合适的索引类型 :根据查询需求选择合适的索引类型,如B-Tree索引、哈希索引、空间索引或全文索引。
-
为常用查询列创建索引 :根据实际查询需求,为常用查询条件和排序列创建索引。
-
避免过度索引 :过多的索引可能会降低写操作性能并占用额外的存储空间。在创建索引时,要权衡查询优化和空间、性能成本。
-
定期评估索引效果 :通过使用慢查询日志、性能监控工具和EXPLAIN语句,定期评估索引的效果并调整索引策略。
面试官:能说说看Innodb的B-Tree索引的结构和索引的过程?
Innodb的B-Tree索引采用B+树这一数据结构。关于B+树的详细介绍可以参考:
字节终面:说说看B树和B+树的理解和区别?在B+树中,如何通过减少磁盘I/O操作来提高查找效率?
以下是InnoDB的B+树索引的结构和索引过程的详细解释:
一、B+树索引的结构
下图所示是一个主键索引,一个索引对应一棵B+树,这些B+树的节点由页组成,通过指针相互连接。

- 节点与页 :
* 在InnoDB中,B+树的每个节点对应于磁盘上的一个页(Page),页是InnoDB管理存储空间的基本单位,一个页的大小一般为16KB。
* 每个页中包含多条记录,这些记录按照键值(通常是主键或索引列的值)的大小进行排序。
* 如下图所示是Innodb索引中的一个数据页,该数据页中包含4条数据。
* 
- 叶子节点与非叶子节点 :
* B+树的叶子节点存储了实际的数据记录或指向数据记录的指针。
* 非叶子节点则存储了索引的键值以及指向子节点的指针,用于引导搜索过程。
- 页目录 :
* 为了加快搜索速度,InnoDB在每个页中建立了页目录(Page Directory)。
* 页目录将页中的记录划分为多个组,每个组的最后一条记录的头信息中包含该组内记录的数量(n_owned)。
* 页目录存储了每个组的最后一条记录的地址偏移量,这些偏移量被称为槽(Slot)。
- 特殊记录 :
* 在每个页中,InnoDB还包含了两个特殊的记录:最小记录(Infimum Record)和最大记录(Supremum Record)。
* 这两条记录分别代表页中记录的最小值和最大值,它们位于记录链表的头和尾。
二、索引过程
- 搜索目标记录 :
* 当需要查找某个目标记录时,InnoDB会首先从根节点(即某个页)开始搜索。
* 使用二分查找法,在页目录中找到一个槽,该槽对应的记录键值最接近但不大于目标键值。
* 然后,InnoDB会沿着该槽指向的子节点继续搜索,直到到达叶子节点。
- 遍历叶子节点 :
* 在叶子节点中,InnoDB会按照键值的大小顺序遍历记录,直到找到目标记录或确定目标记录不存在。
* 如果找到了目标记录,InnoDB会返回该记录的数据或指针。
- 范围查询 :
* 对于范围查询(如查找某个键值范围内的所有记录),InnoDB会利用B+树叶子节点之间的链表结构进行遍历。
* 从找到的第一个符合条件的记录开始,沿着链表向后遍历,直到找到最后一个符合条件的记录或遍历完所有记录。
- 插入与更新 :
* 当插入或更新记录时,InnoDB会首先找到应该插入或更新的叶子节点。
* 如果叶子节点有足够的空间,InnoDB会直接在叶子节点中插入或更新记录。
* 如果叶子节点没有足够的空间,InnoDB会进行页分裂操作,将记录分配到两个新的页中,并更新父节点的指针。
- 删除 :
* 当删除记录时,InnoDB会标记该记录为已删除(而不是立即从页中移除)。
* 随着时间的推移和新的插入操作,已删除的记录可能会被后台的清理线程物理删除。
面试官:什么是聚簇索引和非聚簇索引?他们的区别是什么?
聚簇索引(Clustered Index)和非聚簇索引(Non-clustered
Index)是数据库中的两种基本索引类型,它们在数据的物理存储和查询性能上具有显著的区别。
聚簇索引
聚簇索引是一种数据存储方式,它将索引和数据行一起存储在磁盘上,即索引的叶子节点存储着数据本身。这意味着数据行的物理顺序与索引的逻辑顺序一致。在数据库中,每个表只能有一个聚簇索引,因为在数据行本身只能按照一种方式物理存储。
非聚簇索引
非聚簇索引则将索引和数据行分开存储,索引的叶子节点存储着指向数据行的指针。这种索引类型在数据库中可以有多个,因为数据行的物理顺序与索引的逻辑顺序可以不一致。
区别总结
-
数据存储方式 :聚簇索引将数据和索引一起存储,数据行的物理顺序与索引的逻辑顺序一致;而非聚簇索引则将索引和数据分开存储。
-
索引数量 :每个表只能有一个聚簇索引,但可以有多个非聚簇索引。
面试官:能说说回表的概念,回表的过程是怎么样的?
回表主要涉及到非聚集索引(也称为二级索引)和聚集索引(也称为主键索引)之间的交互。
以下是对回表概念及其过程的详细解释:
一、回表的概念
在InnoDB存储引擎中,数据实际上是按照主键顺序存储在聚集索引(B+树)的叶子节点中的。而非聚集索引(B+树)的叶子节点则存储的是索引列的值和对应的主键值。当执行一个查询时,如果查询条件匹配的是非聚集索引的列,那么InnoDB会首先使用非聚集索引来定位到满足条件的记录的主键值。然而,由于非聚集索引不包含完整的行数据,因此InnoDB需要再次使用这些主键值去聚集索引中查找完整的行数据。这个过程就被称为“回表”。
二、回表的过程
回表的过程可以分为以下几个步骤:
-
索引扫描 :查询首先会尝试使用非聚集索引来定位数据。这涉及到遍历非聚集索引的B+树结构,找到满足查询条件的索引条目。
-
获取主键 :当找到满足查询条件的索引条目时,InnoDB会在非聚簇索引获取对应的主键值。这些主键值是非聚集索引叶子节点中存储的。
-
回表到聚集索引 :由于非聚集索引不包含所有列的信息,InnoDB需要使用这些主键值去聚集索引中查找完整的行记录。这涉及到再次查找聚集索引的B+树结构。
-
获取完整行数据 :通过聚集索引,InnoDB可以找到对应的行,并返回查询所需的全部列。这个过程完成了从非聚集索引到聚集索引的查找,并获取了完整的行数据。
三、回表的影响
回表操作可能会导致性能下降,特别是在大量回表操作时。因为这涉及到额外的磁盘I/O操作,需要多次访问存储介质来读取数据。为了优化查询性能,数据库设计者通常会尽量避免回表。例如,通过使用覆盖索引(Covering
Index)来优化查询。覆盖索引是指索引包含了查询所需的所有列,这样就可以直接从索引中获取数据,而无需回表。
面试官:什么是覆盖索引和索引下推,说说看他们解决了什么问题?能给出使用到了覆盖索引和索引下推的具体例子吗?
覆盖索引和索引下推是MySQL数据库中用于优化查询性能的重要技术。以下是对这两个概念的详细解释以及它们解决的问题:
一、覆盖索引
-
定义 :
覆盖索引是指一个查询语句在执行时,所需的数据可以完全通过索引来获取,而无需访问实际的数据行。也就是说,查询语句所需的列都包含在了创建的索引中,不需要再去查询实际的数据行,从而提高查询性能。 -
解决的问题 :
* 减少I/O操作 :通过直接从索引中获取所需数据,避免了回表访问主键索引中数据行带来的额外I/O开销。
* 提高查询速度 :由于无需访问数据行,查询速度得以提升,特别是在处理大量数据时效果更为显著。
二、索引下推(Index Condition Pushdown, ICP)
-
定义 :所谓的索引条件下推是指在二级索引(即非聚簇索引)中就尽可能根据sql条件减少在二级索引匹配到的记录数,从而有效减少回表的次数。
-
解决的问题 :
* 在二级索引减少数据读取量 :通过在二级索引做了部分过滤操作,避免了将不符合条件的数据行读取到内存中回表,提升了回表的效率。
* 降低内存消耗 :由于减少了需要传递给查询引擎的数据量,内存消耗也相应降低。
以下分别是使用覆盖索引和索引下推的具体例子:
覆盖索引的例子
假设有一个名为 employees 的表,其结构如下:
CREATE TABLE `orders` ( `order_id` INT PRIMARY KEY, `customer_id` INT, `product_id` INT, `order_date` DATE, INDEX idx_customer_product(`customer_id`, `product_id`) );
并且已经插入了一些数据:
INSERT INTO employees (name, age, salary) VALUES (‘Alice’, 30, 60000.00), (‘Bob’, 24, 50000.00), (‘Charlie’, 28, 70000.00), (‘David’, 35, 80000.00), (‘Eve’, 29, 70000.00);
现在,我们为name和age列创建一个联合索引:
CREATE INDEX idx_name_age ON employees(name, age);
然后,我们执行以下查询:
SELECT name, age FROM employees WHERE name = 'Alice';
`
在这个查询中,我们使用了name作为条件,因此查询时会到idx_name_age这个非聚簇索引上进行条件查找。
然而由于select时只选择了name和age两个列,由于这两个列的具体值都在非聚簇索引idx_name_age中,因此MySQL只需扫描 idx_name_age这棵B+树 索引就能返回结果,而无需回表到主键索引访问数据行。这就是覆盖索引的作用。
索引下推的例子
假设有一个名为 orders 的表,其结构如下:
CREATE TABLE `orders` ( `order_id` INT PRIMARY KEY, `customer_id` INT, `product_id` INT, `order_date` DATE, INDEX idx_customer_product(`customer_id`, `product_id`, `order_date`) );
现在有一个查询:
SELECT * FROM orders WHERE customer_id = 123 AND order_date > ‘2020-01-01’;
`
在没有启用索引下推的情况下,MySQL可能会首先使用二级索引idx_customer_product找到所有customer_id = 123
的记录的主键id,假如符合 customer_id = 123 的记录有1000条, 然后数据库会对着1000条记录回表查询对应的满足
order_date > '2020-01-01’这个条件的记录。
然而,启用索引下推后,MySQL会将 order_date > '2020-01-01' 这个条件在二级索引就做判断。在扫描 idx_customer_product 索引时,不仅能匹配 customer_id ,同时也会在索引内直接判断 order_date
是否大于 '2020-01-01' , 因为 order_date 这个字段也保存在了二级索引 idx_customer_product 中。
假如在二级索引经过这两个条件过滤后得到的记录只剩下100条,就只需要对这100条记录回表。
这种优化意味着MySQL能够在访问实际数据页之前,提前在二级索引内部完成更多条件的过滤,极大地提升了查询效率。
面试官:联合索引(组合索引/复合索引)是什么?使用时有什么注意事项?
联合索引(又称组合索引、复合索引)是指对数据库表上的多个列进行索引。
以下是关于联合索引的详细解释和使用时的注意事项:
联合索引的定义
-
在单个列上创建的索引称为单列索引,而在两个或更多个列上创建的索引则称为联合索引。
-
联合索引的创建方法与单个索引相似,但需要在创建时指定多个列。
联合索引的使用原则
1. 最左前缀原则
- 联合索引在查询时,只有按照索引的最左边的列开始查询时,索引才会生效。也就是说,如果联合索引由多列组成,那么查询条件中必须包含索引的最左列,索引才能被使用。
例如,对于联合索引(col1, col2,
col3),当查询条件中包含col1时,索引会被使用;当只包含col2或col3时,索引不会被使用。此外,如果查询条件包含col1和col2,那么索引同样会被使用。
2. 列顺序的重要性
-
在创建联合索引时,列的顺序非常重要。因为联合索引的查询匹配是从左到右的,所以应将选择性高的列放在索引的前面,以提高索引的利用率。
-
选择性高的列意味着该列中的不同值较多,因此可以更有效地缩小查询范围。
3. 避免函数和表达式操作
- 在查询条件中,如果对联合索引的列进行了函数操作或表达式运算,那么索引可能会失效。因为索引是基于列的原始值进行排序和存储的,而函数操作或表达式运算会改变列的值或形式,导致索引无法匹配。
4. 合理使用LIKE关键字
-
当使用LIKE关键字进行模糊查询时,如果“%”放在第一个位置(即前缀匹配),索引将不会生效。因为索引无法预测前缀的变化,所以无法有效地利用索引进行匹配。
-
如果“%”放在后面(即后缀匹配)或中间(即包含匹配),但前面有确定的字符,那么索引可能会被部分使用,具体取决于数据库的实现和查询优化器的决策。
5. 索引的选择性
-
索引的选择性是指索引列中不同值的数量与表中总记录数的比例。选择性越高,索引的区分度越好,查询效率也越高。
-
在创建联合索引时,应优先考虑选择性高的列。如果两个列的选择性相近,那么可以考虑将查询条件中更常用的列放在前面。
6. 索引的维护成本
-
虽然索引可以提高查询效率,但也会增加插入、更新和删除操作的维护成本。因为每次修改数据时,都需要更新相应的索引。
-
因此,在创建索引时,需要权衡查询效率和维护成本之间的关系。对于经常修改的表,应谨慎添加过多的索引。
7. 考虑查询模式
-
在创建联合索引时,还需要考虑实际的查询模式。如果某些查询条件经常一起出现,那么可以将这些列组合成一个联合索引来提高查询效率。
-
此外,还需要考虑查询的排序和分组需求。如果查询结果需要按照某个或多个列进行排序或分组,那么可以将这些列包含在联合索引中以提高性能。
联合索引的示例
假设有一个表 employees ,包含字段 a 、 b 和 c ,并创建了联合索引 idx_a_b_c (a,
b, c)。以下是一些查询示例及其是否使用索引的情况:
-
SELECT * FROM employees WHERE a = 1 AND b = 2 AND c = 3:此查询将使用联合索引idx_a_b_c。 -
SELECT * FROM employees WHERE a = 1 AND b > 2:此查询将使用联合索引idx_a_b_c中的a和b列。 -
SELECT * FROM employees WHERE b = 2 AND c = 3:此查询不会使用联合索引idx_a_b_c,因为缺少最左列a。
面试官:说说看索引失效的情况有哪些?如果我对”性别“字段建立索引能有效使用索引吗?
索引失效是指在数据库查询过程中,由于某些原因,索引无法被数据库查询优化器有效利用,导致查询性能下降的情况。以下是一些常见的索引失效情况:
- 查询中使用了不等操作符 :
* 当查询条件中使用了“!=”或“<>”等不等操作符时,索引可能会失效。这是因为数据库需要逐行扫描来查找不满足条件的行,导致索引无法被有效利用。
- 对索引字段进行了函数处理 :
* 如果在查询中对索引字段使用了函数(如DATE()、UPPER()、LOWER()等),索引将失效。因为数据库需要先对每行数据应用函数,然后再进行比较,这使得索引无法被直接使用。
- 数据类型不匹配 :
* 当查询条件中的数据类型与索引字段的数据类型不匹配时,索引可能失效。数据库在比较不同类型的数据时,可能会进行类型转换,而转换过程可能导致索引无法被正确使用。
- 查询列不在索引列中 :
* 如果查询条件中的列不是索引列,或者查询的列没有包含在联合索引中,那么索引将无法被使用。
- NULL值的处理 :
* 如果索引字段包含NULL值,并且在查询条件中也对NULL值进行了处理(如使用IS NULL或IS NOT NULL),那么索引可能会失效。因为数据库在处理NULL值时的行为是未定义的,导致索引无法被有效利用。
- 联合索引未按顺序使用 :
* 对于联合索引,必须按照索引定义的顺序进行查询,否则索引可能失效。例如,如果联合索引是按(A, B)顺序创建的,那么在查询时必须同时使用A列和B列作为条件或者只使用A列作为条件。如果直接使用B列进行查询,索引将不会被使用。
- 索引列上进行了计算 :
* 如果在查询中对索引列进行了计算(如加减乘除、字符串连接等),索引将失效。因为数据库需要先对每行数据进行计算,然后再进行比较,这使得索引无法被直接使用。
- 使用了低选择性列 :
* 索引在高选择性列上更有效,因为高选择性意味着每个值在表中出现的次数较少,因此索引可以更快速地过滤数据。相反,在低选择性列(如性别、布尔值等)上创建索引,效果可能会很差,因为选择性太低,数据库可能会倾向于进行全表扫描而不是使用索引。
- 使用了隐式转换 :
* 当查询条件中的数据类型与索引字段的数据类型不匹配时,数据库可能会进行隐式转换,从而导致索引失效。例如,如果索引字段是字符串类型,而查询条件中使用的是数值类型,数据库会进行隐式转换,导致索引无法被利用。
- 统计信息不准确 :
* 数据库的查询优化器依赖于统计信息来决定是否使用索引。如果统计信息不准确或过时,优化器可能会做出错误的决定,从而导致索引失效。因此,需要定期更新数据库的统计信息以确保优化器能够做出正确的决策。
如果对“性别”字段建立索引,通常情况下并不能有效使用索引来提高查询性能,因为“性别”字段的值通常只有有限的几种(如男、女),这意味着该字段的选择性非常低。选择性是指索引列中不同值的数量与表中总记录数的比例,选择性越高,索引的区分度越好,查询效率也越高。由于“性别”字段的选择性很低,因此即使为其建立索引,数据库查询优化器也可能选择进行全表扫描而不是使用索引,因为全表扫描可能更快地找到所需的记录。
面试官:如果线上存在慢sql,该怎么排查和优化?
当线上存在慢SQL时,排查和优化的过程可以遵循以下步骤:
一、排查慢SQL
- 开启慢查询日志 :
* 首先,需要确保MySQL的慢查询日志已经开启。可以通过执行 ` SHOW VARIABLES LIKE '%slow_query_log%' ` 来检查慢查询日志是否开启。
* 如果未开启,可以通过执行 ` SET GLOBAL slow_query_log = 1; ` 来开启慢查询日志。
* 同时,可以设置 ` long_query_time ` 参数来定义慢查询的阈值,例如 ` SET GLOBAL long_query_time = 5; ` 表示执行时间超过5秒的查询将被记录为慢查询。
- 查看慢查询日志 :
* 通过慢查询日志,可以查看哪些SQL语句执行时间较长。
* 分析这些慢查询语句,找出可能的性能瓶颈。
- 使用EXPLAIN分析执行计划 :
* 对慢查询语句使用 ` EXPLAIN ` 关键字,查看其执行计划。
* 分析执行计划中的各个步骤,找出可能的性能问题,如全表扫描、排序操作等。
- 检查索引 :
* 确保查询中涉及的字段上有适当的索引。
* 检查索引是否被正确使用,是否存在索引失效的情况。
- 监控数据库性能 :
* 使用数据库监控工具或系统监控工具来监控数据库的CPU、内存、磁盘I/O等资源使用情况。
* 确定是否存在资源瓶颈,如CPU使用率过高、内存不足等。
二、优化慢SQL
- 优化SQL语句 :
* 改写查询条件,避免不必要的全表扫描。
* 合理使用索引,确保查询能够命中索引。
* 分解复杂的查询语句,将其拆分为多个简单的查询语句。
- 添加或修改索引 :
* 根据查询需求,为相关字段添加合适的索引。
* 对已存在的索引进行优化,如调整索引列的顺序、删除不必要的索引等。
- 调整数据库配置 :
* 根据实际情况调整数据库的配置参数,如缓冲池大小、并发连接数等。
* 优化数据库的内存分配和缓存策略,提高查询性能。
- 使用缓存 :
* 对于频繁读取的热点数据,可以使用缓存技术(如Redis、Memcached等)来减少数据库的访问次数。
- 分库分表 :
* 如果数据库中的数据量过大,可以考虑对数据库进行分库分表操作。
* 通过分散数据存储和查询的压力,提高数据库的性能和响应时间。
- 优化硬件资源 :
* 如果硬件资源不足,可以考虑升级硬件或进行扩容操作。
* 增加CPU、内存、磁盘等硬件资源,提高数据库的处理能力。
- 定期维护数据库 :
* 定期清理无用的数据,保持表数据量在合理范围内。
* 优化数据库的结构,如重建索引、更新统计信息等。
下面是一个具体诊断慢sql的例子:
一、诊断慢SQL
假设我们有一个查询语句如下:
** SELECT * FROM orders WHERE customer_id = 12345 AND order_date BETWEEN
‘2023-01-01’ AND ‘2023-12-31’ ** ;
这个查询语句执行得很慢,我们需要进行诊断。
- 使用EXPLAIN分析执行计划 :
执行 EXPLAIN 命令来查看查询的执行计划:
explain ** SELECT * FROM orders WHERE customer_id = 12345 AND order_date
BETWEEN ‘2023-01-01’ AND ‘2023-12-31’ ** ;
查看输出结果,特别是 type 、 possible_keys 、 key 、 rows 和 Extra 列。
假设输出结果显示: 这表明查询没有使用索引,而是进行了全表扫描,这通常会导致查询性能低下。
type: ALL(全表扫描)possible_keys: NULL(没有可用的索引)key: NULL(没有使用索引)rows: 1000000(估计需要扫描100万行)Extra: Using where(使用WHERE子句进行过滤)
- 检查索引 :
查看 orders 表上的索引情况,确保 customer_id 和 order_date 字段上有索引。
SHOW INDEX FROM orders;
假设结果显示 customer_id 和 order_date 字段上没有索引。
二、优化慢SQL
- 添加索引 :
根据诊断结果,我们需要在 customer_id 和 order_date
字段上添加索引。由于这是一个复合查询条件,我们可以考虑创建一个复合索引。
** CREATE INDEX idx_customer_order_date ON orders(customer_id, order_date);
这个索引将首先按 customer_id 排序,然后按 order_date 排序。这将有助于加快查询速度,因为查询条件同时涉及这两个字段。
- 重新执行查询并验证性能 :
在添加索引后,重新执行原始查询语句,并观察执行时间是否有所减少。如果查询速度显著提高,说明优化是有效的。
- 使用EXPLAIN验证优化效果 :
再次使用 EXPLAIN 命令来查看查询的执行计划,确保查询现在使用了新添加的索引。
** EXPLAIN SELECT * FROM orders WHERE customer_id = 12345 AND order_date
BETWEEN ‘2023-01-01’ AND ‘2023-12-31’; **
查看输出结果,确保 type 列的值不再是 ALL ,而是 range 或 ref 等更高效的类型,并且 key
列的值显示为新添加的索引名称 idx_customer_order_date 。
欢迎在评论区留言表达看法 或 提出你想学习的技术内容 与 面试问题,阿沛会一一作出回复。
如果本文对大家有帮助,麻烦大家动动小手点个免费的“赞”或“在看”,大家的鼓励就是阿沛持续更新的动力~

-- 往期精彩 –
字节终面:说说看B树和B+树的理解和区别?在B+树中,如何通过减少磁盘I/O操作来提高查找效率?