☰
数据库索引详解
2026/10/17 14:34:37 网站建设 项目流程

目录

  • 前言
  • 一、什么是数据库索引?
    • 1.1 索引的基本概念
    • 1.2 索引解决了什么问题?
    • 1.3 索引的优点与代价
  • 二、数据库索引的底层原理
    • 2.1 为什么不能总是全表扫描?
    • 2.2 常见索引数据结构
      • 1. 哈希索引(Hash Index)
      • 2. 二叉搜索树(BST)
      • 3. AVL 树与红黑树
      • 4. B 树与 B+ 树
    • 2.3 为什么 MySQL 选择 B+ 树?
      • B+ 树的查询复杂度
    • 2.4 InnoDB 的两种重要索引:聚簇索引和二级索引
      • 1. 聚簇索引(Clustered Index)
      • 2. 二级索引(Secondary Index)
    • 2.5 什么是覆盖索引?
  • 三、数据库索引的主要类型
    • 3.1 按功能划分
    • 3.2 主键索引
    • 3.3 普通索引
    • 3.4 唯一索引
    • 3.5 联合索引
  • 四、如何创建、查看和删除索引?
    • 4.1 创建索引的四种常见方式
      • 方式一:创建表时定义主键和索引
      • 方式二:创建普通索引
      • 方式三:创建唯一索引
      • 方式四:创建联合索引
    • 4.2 查看表中有哪些索引
    • 4.3 删除索引
    • 4.4 如何判断索引是否有必要?
  • 五、联合索引最重要的规则:最左前缀原则
    • 5.1 什么是最左前缀原则?
    • 5.2 哪些 SQL 能利用这个联合索引?
    • 5.3 为什么联合索引的字段顺序如此重要?
    • 5.4 联合索引字段顺序应该怎么安排?
    • 5.5 范围查询对联合索引有什么影响?
  • 六、哪些 SQL 写法可能导致索引无法有效使用?
    • 6.1 在索引字段上使用函数
    • 6.2 对索引字段进行计算
    • 6.3 使用 `LIKE '%关键字%'`
    • 6.4 隐式类型转换
    • 6.5 `OR` 条件

前言

数据库索引是 Java 后端开发中非常重要的知识点。无论你使用 MySQL、MyBatis-Plus,还是在 Spring Boot 项目中编写复杂的查询 SQL,理解索引都能帮助你解决慢 SQL、分页查询性能差、联合索引失效等实际问题。

这篇文章以 MySQL 8.0 + InnoDB 存储引擎 为主要讲解对象,结合电商订单、企业用车订单等业务场景,从基础概念讲到 B+ 树底层原理,再到索引设计、SQL 编写规范和性能排查。

关于本文,你可以学到:

  • 什么是数据库索引?为什么它能够提高查询速度?
  • MySQL 为什么主要使用 B+ 树,而不是普通二叉树、哈希表?
  • 聚簇索引、二级索引、联合索引、覆盖索引分别是什么?
  • 为什么联合索引有最左前缀原则?
  • 为什么对索引字段使用函数,可能导致索引失效?
  • 如何正确创建索引?索引越多越好吗?
  • 如何使用EXPLAIN分析 SQL 是否使用了索引?
  • 在 Java 后端项目中,应该遵守哪些 SQL 索引规范?

一、什么是数据库索引?

1.1 索引的基本概念

数据库索引(Index)是一种帮助数据库快速定位数据的数据结构。

我们可以把它理解成一本书的目录。

书籍目录
通过章节名称和页码,快速找到需要的内容。

数据库索引
通过索引键值和数据位置,快速定位数据库记录。

假设我们有一张用户表user,里面存储了 100 万个用户。

CREATE TABLE user ( id BIGINT PRIMARY KEY, username VARCHAR(100), age INT, email VARCHAR(200) );

现在需要查询用户名为zhangsan的用户:

SELECT * FROM user WHERE username = 'zhangsan';

如果username没有索引,数据库可能需要从大量记录中逐行检查用户名是否匹配。

如果username上存在合适的索引,数据库就有机会通过索引快速找到匹配记录,而不需要检查整张表。

创建索引:

CREATE INDEX idx_user_username ON user (username);

这样,数据库就拥有了一份按照username组织的索引结构。

注意:创建索引不意味着每条 SQL 都一定使用索引。 优化器会根据查询条件、数据分布、索引选择性和预估成本,决定采用哪种执行计划。

1.2 索引解决了什么问题?

数据库查询通常涉及两个过程:

  1. 找到符合条件的数据。
  2. 读取这些数据的完整记录,或者返回所需字段。

索引主要优化第一个过程,也可能通过覆盖索引同时避免第二个过程。

例如:

SELECT * FROM user WHERE id = 10001;

如果id是主键,InnoDB 可以利用主键索引直接定位记录。

再看:

SELECT * FROM user WHERE age = 25;

如果age没有索引,数据库可能需要扫描整张表;如果有合适的索引,就可以通过索引查找符合条件的记录。

但并不是所有场景下索引都更快。例如,查询 80% 的数据时,使用索引后仍然需要大量回表,优化器可能认为全表扫描更划算。

1.3 索引的优点与代价

优点说明
提高查询效率减少需要扫描的数据
加速排序合适的索引可能避免额外排序
加速分组某些GROUP BY可以利用索引顺序
支持唯一约束唯一索引可以防止重复键值

索引也有成本:

  • 占用额外的磁盘空间和 Buffer Pool 内存。
  • 插入数据时需要维护索引。
  • 更新索引字段时,可能需要调整索引结构。
  • 删除数据时,也需要维护对应索引。
  • 索引设计不合理会增加优化器选择和维护成本。

因此,索引优化的目标不是“给所有字段都创建索引”,而是用合理的索引支撑高频、重要的查询,同时控制写入和存储成本。

二、数据库索引的底层原理

理解索引为什么快,关键在于理解数据是如何组织的。

2.1 为什么不能总是全表扫描?

假设有 100 万条用户记录,需要查询id = 900000。

如果数据库没有可用索引,它可能需要检查大量记录才能确认结果。

在理想化的逐条检查模型下,最坏情况下需要检查 100 万条记录。

如果表按照主键建立了合适的 B+ 树索引,查找过程则类似于不断缩小搜索范围。

这两种方式的差别可以简单理解为:

真实查询的耗时还取决于磁盘 I/O、缓存命中、回表次数、结果集大小和并发负载,并不只取决于比较次数。

2.2 常见索引数据结构

1. 哈希索引(Hash Index)

哈希索引通过哈希函数,把键值映射到相应的数据位置。

例如:

user_id = 1001 → 位置 A user_id = 1002 → 位置 B user_id = 1003 → 位置 C

理想情况下,哈希索引可以非常高效地处理等值查找:

SELECT * FROM user WHERE id = 1001;

但它存在一些局限:

  • 不适合普通的范围查找,例如id BETWEEN 1000 AND 2000。
  • 不适合依靠索引顺序完成排序。
  • 哈希冲突需要额外处理。
  • 不支持 B+ 树那样的有序范围遍历。

MySQL InnoDB 的常规表索引主要使用 B+ 树。InnoDB 还支持自适应哈希索引,但它是存储引擎内部根据访问模式建立的优化机制,不等于用户可以任意创建的普通哈希索引。

2. 二叉搜索树(BST)

二叉搜索树的特点是:

  • 左子树的键值小于节点。
  • 右子树的键值大于节点。

如果树比较平衡,查询效率可以达到 \(O(\log N)\)。

但是,如果插入的数据长期有序,普通二叉搜索树可能退化成链表,查询效率接近 \(O(N)\)。

3. AVL 树与红黑树

AVL 树和红黑树通过平衡机制,避免普通二叉搜索树严重退化。

不过,对于存储在磁盘上的大型数据库索引,它们通常不是最理想的主索引结构。

原因在于:二叉树每个节点通常只有少量分支,查找深层数据可能需要访问更多节点。而磁盘访问的代价远高于内存中的简单比较。

数据库希望一个节点能够容纳很多键值,尽量减少树的高度。

4. B 树与 B+ 树

B 树和 B+ 树都是多路平衡搜索树,适合磁盘或分页存储环境。

它们的关键优势是:一个节点可以包含多个键值和多个子节点,从而让树保持较低的高度。

InnoDB 的主要索引结构是 B+ 树。

2.3 为什么 MySQL 选择 B+ 树?

B+ 树是理解 InnoDB 索引的核心。

它有以下几个重要特点:

  1. 多路分支:一个节点可以存储多个键值,拥有多个子节点。
  2. 树高较低:相比二叉树,通常可以用更少的层数定位数据。
  3. 叶子节点有序:叶子节点中的键值按顺序组织,适合范围查询。
  4. 叶子节点之间通常通过双向链表连接:方便顺序遍历。
  5. InnoDB 聚簇索引的叶子节点存储完整的行数据,而二级索引的叶子节点存储索引键和对应的主键值。

例如,一棵简化的 B+ 树可能如下:

假设我们执行:

SELECT * FROM user WHERE id = 90;

数据库会从根节点开始,根据键值决定向哪个子节点查找,最终到达包含90的叶子节点。

如果查询的是:

SELECT * FROM user WHERE id BETWEEN 50 AND 120;

数据库可以先定位范围起点,再沿叶子节点的有序链表向后读取符合条件的记录。

这就是 B+ 树既适合等值查询,也适合范围查询的重要原因。

B+ 树的查询复杂度

在理想化的平衡树模型中,定位某个键值通常可以近似理解为 \(O(\log N)\)。

但要注意:这并不意味着每条查询只需要一次磁盘读取。实际访问次数还取决于树高、节点是否在缓存中、数据是否需要回表等因素。

2.4 InnoDB 的两种重要索引:聚簇索引和二级索引

这是整个索引体系中最重要的知识之一。

1. 聚簇索引(Clustered Index)

InnoDB 的聚簇索引决定了表记录的主要组织方式。

当表有主键时,通常使用主键作为聚簇索引。

例如:

CREATE TABLE user ( id BIGINT PRIMARY KEY, username VARCHAR(100), age INT, email VARCHAR(200) ) ENGINE = InnoDB;

主键索引的叶子节点存储完整的用户记录。

可以将其简化理解为:

主键 B+ 树 | v +--------------------------------+ | id=1001, username=张三, age=25 | +--------------------------------+ | id=1002, username=李四, age=30 | +--------------------------------+ | id=1003, username=王五, age=28 | +--------------------------------+

以上是逻辑示意,不是实际物理页的存储格式。

因此:

SELECT * FROM user WHERE id = 1002;

可以通过主键索引直接找到包含完整记录的叶子节点,不需要再通过另一个索引定位这条记录。

如果没有显式主键,InnoDB 会选择合适的非空唯一索引作为聚簇索引;如果也没有合适的唯一索引,则会创建内部使用的隐藏聚簇索引。

2. 二级索引(Secondary Index)

除了聚簇索引,表还可以建立其他索引。

例如:

CREATE INDEX idx_user_username ON user (username);

这个索引的叶子节点主要保存:

  • username的索引键值。
  • 对应记录的主键值id。

例如:

username 二级索引 李四 → id=1002 王五 → id=1003 张三 → id=1001

当执行:

SELECT * FROM user WHERE username = '李四';

大致执行过程如下:

  1. 先通过idx_user_username找到username = '李四'的索引记录。
  2. 从二级索引记录中获取主键值id = 1002。
  3. 再通过主键索引查找完整的用户记录。

第二步之后再次访问主键索引的过程,通常称为回表。

所以,二级索引可以帮助快速定位记录,但查询不在二级索引中的其他字段时,可能需要回表。

2.5 什么是覆盖索引?

覆盖索引不是一种独立的索引类型,而是一种查询访问方式。

如果一个查询需要的所有字段,都能直接从某个索引中获取,那么这个索引就覆盖了该查询。

假设存在:

CREATE INDEX idx_user_username_age ON user (username, age);

执行:

SELECT username, age FROM user WHERE username = '李四';

因为查询条件需要username,返回字段需要username和age,而这几个字段都在索引中,因此可以直接读取索引完成查询,不需要再访问聚簇索引读取完整记录。

这就是覆盖索引。

在执行计划中,经常可以看到Extra列出现:

Using index

它通常表示查询能够通过索引覆盖所需数据。

对比下面两个查询:

-- 可能使用覆盖索引 SELECT username, age FROM user WHERE username = '李四'; -- 通常需要回表获取其他字段 SELECT * FROM user WHERE username = '李四';

覆盖索引有助于减少随机访问和回表开销,尤其适合高频列表查询。

不过,不应该为了让所有查询都覆盖而把大量字段塞进索引。过宽的索引会增加磁盘占用和写入成本。

image

MySQL开发者专区

+1

三、数据库索引的主要类型

3.1 按功能划分

索引类型作用典型场景
主键索引唯一标识记录,InnoDB 中通常是聚簇索引id
普通索引提高指定字段的查找效率username
唯一索引限制索引键值不能重复email
联合索引同时对多个字段建立索引company_id, status
全文索引支持特定类型的全文检索文章内容搜索

需要注意,以上分类并不完全互斥。例如,主键索引本身也具有唯一性,联合索引也可以是唯一索引。

3.2 主键索引

CREATE TABLE orders ( id BIGINT PRIMARY KEY, order_no VARCHAR(64), amount DECIMAL(12, 2) );

主键必须唯一且不能为NULL。

主键索引不仅用于查找,还决定了 InnoDB 聚簇索引的组织方式。

因此,主键设计通常应该:

  • 保证唯一性。
  • 尽可能稳定,避免频繁更新。
  • 尽量简洁,避免不必要地使用很宽的主键。
  • 在大量插入场景下,评估键值的插入模式对页分裂和写入性能的影响。

自增整数是常见的选择,但并非所有业务都必须使用自增主键。

3.3 普通索引

CREATE INDEX idx_orders_order_no ON orders (order_no);

普通索引不要求索引键值唯一。

例如,多个订单可能具有相同的某个业务分类字段,因此普通索引适合这类查询。

SELECT * FROM orders WHERE order_no = 'ORD20261015001';

3.4 唯一索引

CREATE UNIQUE INDEX uk_orders_order_no ON orders (order_no);

唯一索引除了能够加速查询,还能保证非NULL的索引键组合不重复。

例如,业务要求订单号不能重复,就应该通过数据库唯一约束保证,而不是只在 Java 代码中先查询一次再插入。

因为“先查后插”在并发场景下仍可能产生竞态条件。

注意:MySQL 的唯一索引允许存在多个NULL值,具体行为还需要结合字段定义与业务约束理解。

3.5 联合索引

联合索引也叫复合索引,是对多个字段共同建立的索引。

例如:

CREATE INDEX idx_orders_company_status_time ON orders (company_id, status, create_time);

它的索引顺序是:

company_id → status → create_time

这个顺序非常重要。

联合索引并不是给三个字段分别创建三个独立索引,而是将多个字段按指定顺序组合成索引键。

它特别适合固定业务查询模式,例如:

SELECT id, order_no, amount FROM orders WHERE company_id = 1001 AND status = 1 ORDER BY create_time DESC;

该 SQL 的过滤和排序条件与联合索引较为匹配,但实际执行效果仍需要通过EXPLAIN验证。

联合索引的设计原则,将在后文详细说明。

四、如何创建、查看和删除索引?

4.1 创建索引的四种常见方式

方式一:创建表时定义主键和索引

CREATE TABLE orders ( id BIGINT NOT NULL AUTO_INCREMENT, order_no VARCHAR(64) NOT NULL, company_id BIGINT NOT NULL, status TINYINT NOT NULL, amount DECIMAL(12, 2) NOT NULL, create_time DATETIME NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_orders_order_no (order_no), KEY idx_orders_company_status_time ( company_id, status, create_time ) ) ENGINE = InnoDB;

这是新建表时最清晰的方式之一。

方式二:创建普通索引

CREATE INDEX idx_orders_status ON orders (status);

也可以使用:

ALTER TABLE orders ADD INDEX idx_orders_status (status);

两种方式都可以用于给现有表添加普通索引。

方式三:创建唯一索引

CREATE UNIQUE INDEX uk_user_email ON user (email);

执行之前要先确认现有数据是否违反唯一性要求,否则创建操作可能失败。

方式四:创建联合索引

CREATE INDEX idx_orders_company_status_time ON orders (company_id, status, create_time);

字段的先后顺序决定了索引的组织顺序,不能随意调换。

MySQL 支持多种索引定义方式,具体语法可参考官方文档。

image

MySQL开发者专区

4.2 查看表中有哪些索引

SHOW INDEX FROM orders;

或者:

SHOW CREATE TABLE orders;

其中,SHOW INDEX可以查看索引名称、唯一性、索引字段顺序等信息。

重点关注:

  • Key_name:索引名称。
  • Non_unique:是否允许重复。
  • Seq_in_index:字段在联合索引中的顺序。
  • Column_name:索引包含的字段。
  • Cardinality:索引统计信息中的基数估计值。

4.3 删除索引

DROP INDEX idx_orders_status ON orders;

也可以通过ALTER TABLE:

ALTER TABLE orders DROP INDEX idx_orders_status;

删除索引之前,要确认没有其他重要 SQL 依赖它带来的性能收益。

生产环境还要考虑索引 DDL 对锁、I/O、复制延迟和业务流量的影响。大表建索引不应该不经评估就直接在高峰期执行。

4.4 如何判断索引是否有必要?

不要只根据“这个字段出现在WHERE中”就创建索引。

应该综合考虑:

  1. 查询是否高频。
  2. 表的数据量是否足够大。
  3. 条件能过滤掉多少记录。
  4. 是否存在可复用的联合索引。
  5. 查询是否需要排序、分页或关联其他表。
  6. 索引会带来多少写入和存储成本。

例如,status只有 0、1 两个值。如果某个值占了绝大多数记录,那么单独对status建索引未必划算。

但如果它和公司编号、创建时间组合成联合索引,仍可能非常有价值。

关键是看具体查询模式和数据分布,而不是孤立判断某个字段。

五、联合索引最重要的规则:最左前缀原则

这部分是面试和实际开发中最容易遇到的问题。

5.1 什么是最左前缀原则?

假设我们建立联合索引:

CREATE INDEX idx_orders_company_status_time ON orders (company_id, status, create_time);

可以把它理解为索引键按照以下顺序组织:

第一层排序依据:company_id 第二层排序依据:status 第三层排序依据:create_time

例如,索引中有以下键值:

company_idstatuscreate_time
100102026-10-01 09:00:00
100102026-10-02 10:00:00
100112026-10-01 08:00:00
100112026-10-03 12:00:00
100202026-10-01 09:00:00

注意:上表只是展示联合索引的排序逻辑,实际物理存储还有其他内部信息。

由于首先按照company_id排序,所以同一个公司的数据聚集在一起;公司相同的情况下,再按照status排序;前两个字段相同时,最后才按照create_time排序。

因此,这个索引天然适合从最左边的字段开始定位。

5.2 哪些 SQL 能利用这个联合索引?

查询一:WHERE company_id = 1001

(匹配最左前缀) 可以利用联合索引的第一列定位数据。

查询二:WHERE company_id = 1001 AND status = 1

(匹配最左前缀) 可以利用前两列缩小查找范围。

查询三:WHERE company_id = 1001 AND status = 1 AND create_time >= ‘2026-10-01’

(匹配最左前缀) 三个字段均有条件,可以利用三个索引列进行定位或范围扫描。

查询四:WHERE status = 1

(缺少最左列条件) 通常无法利用该联合索引直接定位 status = 1 的连续范围。不过,在特定条件下,MySQL 可能采用 Skip Scan 等优化;也可能扫描整个索引。因此不能简单断言绝对不使用索引。

查询五:WHERE company_id = 1001 AND create_time >= ‘2026-10-01’

(中间列缺失) 通常可以利用第一列 company_id 定位范围,但跳过了 status,后面的 create_time 通常不能像完整连续前缀那样直接用于构造精确的索引范围,可能需要额外过滤。

最左前缀原则的核心是:

联合索引按照字段顺序组织数据,越靠左的字段越决定索引的定位能力。

官方文档也说明了多列索引的键值是按照定义顺序组合起来的。

5.3 为什么联合索引的字段顺序如此重要?

看两个索引:

CREATE INDEX idx_a_b_c ON orders (a, b, c); CREATE INDEX idx_b_a_c ON orders (b, a, c);

它们并不等价。

前者优先按照a排序,后者优先按照b排序。

如果系统中最常见的查询是:

WHERE a = ? AND b = ?

那么两种索引都可能支持该查询,但如果还存在:

WHERE a = ?

第一个索引通常更加合适。

而对于:

WHERE b = ?

第二个索引通常更有优势。

设计联合索引时,要根据实际查询组合,而不是仅凭字段名称决定顺序。

5.4 联合索引字段顺序应该怎么安排?

实际设计中,可以综合考虑以下因素:

  1. 查询条件是否经常出现:高频查询优先考虑。
  2. 等值条件与范围条件:通常优先安排稳定出现的等值条件,再考虑范围条件。
  3. 过滤能力:区分度高的字段往往更有利于缩小范围,但不是唯一标准。
  4. 排序与分组需求:考虑ORDER BY、GROUP BY的字段和方向。
  5. 索引复用能力:能覆盖多个重要查询的索引通常更有价值。

例如:

WHERE company_id = ? AND status = ? AND create_time >= ? AND create_time < ? ORDER BY create_time DESC

可以考虑:

CREATE INDEX idx_orders_company_status_time ON orders (company_id, status, create_time);

这里company_id、status是等值条件,create_time是范围条件,同时还用于排序。

这是一个合理的候选索引,但最终仍应通过真实数据与执行计划验证。

5.5 范围查询对联合索引有什么影响?

考虑以下 SQL:

SELECT * FROM orders WHERE company_id = 1001 AND status > 1 AND create_time = '2026-10-15 10:00:00';

如果索引是:

(company_id, status, create_time)

通常可以先根据company_id定位,再根据status构造范围扫描。

由于status已经是范围条件,后面的create_time通常不能继续作为同样意义上的连续索引范围边界。

但这不代表create_time完全没有作用:它仍可能参与索引条件下推、过滤,或者在特定执行计划中发挥作用。

不要把“范围条件之后的列通常不能继续缩小连续扫描区间”误解成“范围条件之后的所有索引列完全失效”。

六、哪些 SQL 写法可能导致索引无法有效使用?

在 Java 后端项目中,很多慢 SQL 并不是因为没有索引,而是因为 SQL 写法没有充分利用已有索引。

下面结合常见场景逐一说明。

6.1 在索引字段上使用函数

假设:

CREATE INDEX idx_orders_create_time ON orders (create_time);

错误或不理想的写法:

SELECT * FROM orders WHERE DATE(create_time) = '2026-10-15';

原因是:

DATE(create_time)

对索引字段应用了函数,传统的普通索引通常不能直接按照原始create_time值构造高效的日期范围。

更推荐改写为左闭右开区间:

SELECT * FROM orders WHERE create_time >= '2026-10-15 00:00:00' AND create_time < '2026-10-16 00:00:00';

这种写法更有利于利用create_time索引进行范围扫描。

在 Java 中,可以使用LocalDate计算当天起始时间和次日零点,再传入 SQL 参数。

如果确实需要频繁按日期表达式查询,MySQL 8.0 也支持函数索引,但需要针对具体表达式和版本设计,不应该默认用函数索引替代简单的范围改写。

6.2 对索引字段进行计算

例如:

SELECT * FROM orders WHERE amount + 100 > 500;

假设amount上有普通索引,这种写法可能让索引范围构造变得困难。

可以在逻辑等价的情况下改为:

SELECT * FROM orders WHERE amount > 400;

这里不仅 SQL 更容易利用索引,业务含义也更加直接。

但需要注意数据类型、精度和NULL语义,确保改写前后确实等价。

6.3 使用LIKE '%关键字%'

假设:

CREATE INDEX idx_user_username ON user (username);

下面这种前缀匹配通常可以利用 B+ 树索引:

SELECT * FROM user WHERE username LIKE 'zhang%';

而这种包含匹配:

SELECT * FROM user WHERE username LIKE '%zhang%';

普通 B+ 树索引通常无法直接定位包含zhang的连续键值范围,可能需要扫描大量记录。

需要全文检索时,可以根据语言、分词、搜索语义和版本考虑FULLTEXT索引或专门的搜索引擎。

不过,MySQL 的全文索引不等同于任意子串匹配,不能简单地认为它能直接替代%关键词%。

6.4 隐式类型转换

假设:

CREATE TABLE user ( id BIGINT PRIMARY KEY, phone VARCHAR(20) ); CREATE INDEX idx_user_phone ON user (phone);

如果phone存储的是字符串手机号,推荐:

SELECT * FROM user WHERE phone = '13800138000';

而不是:

SELECT * FROM user WHERE phone = 13800138000;

第二种写法会引入类型转换问题,可能影响索引使用,还可能改变比较语义。

需要特别注意的是:MySQL 的隐式转换是否影响索引,取决于具体字段类型、比较操作和执行计划,并不是所有类型不一致都会导致索引失效。

规范做法:参数类型尽量与数据库字段类型保持一致。

对于 Java 项目:

  • BIGINT通常对应Long。
  • INT通常对应Integer。
  • VARCHAR通常对应String。
  • DATETIME应使用明确的日期时间类型和统一的时区约定。

6.5OR条件

假设user表分别有idx_user_name和idx_user_phone。

SELECT * FROM user WHERE username = 'zhangsan' OR phone = '13800138000';

这条 SQL 并不一定无法使用索引。

如果两个分支都适合使用索引,MySQL 有机会采用index_merge等执行方式。

但如果其中一个分支缺少索引,或者两个条件的选择性不理想,查询成本可能很高。

因此,不要把“出现 OR 就一定失效”当成规则。

正确做法是:

  1. 确认两个分支的查询条件。
  2. 检查相关字段是否有合适索引。
  3. 使用EXPLAIN查看执行计划。
  4. 必要时评估改写方案,但不能盲目将OR拆成UNION,因为去重语义、排序和执行成本都可能

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询