MySQL的 索引类型 normal、 unique 和 索引方法 btree 、 hash

news/2025/11/22 21:45:22/文章来源:https://www.cnblogs.com/FlyAway2013/p/19258666

 

一、索引类型:Normal(普通索引) vs Unique(唯一索引)

核心差异是 是否对字段值施加「唯一性约束」,其他特性均围绕这一点展开:
 
对比维度Normal(普通索引)Unique(唯一索引)
核心约束 无唯一性要求,字段值可重复 强制字段值唯一,不允许重复(NULL 特殊处理)
NULL 值支持 允许多个 NULL 值(InnoDB/MyISAM 均支持) 仅允许 1 个 NULL 值(InnoDB/MyISAM 通用)
插入 / 更新逻辑 直接执行,无需检查重复 先检查字段值是否已存在,重复则报 Duplicate entry 错误
索引结构 与 Unique 一致(默认 BTree),仅多存储重复值 与 Normal 结构相同,但叶子节点无重复值
性能特点 插入 / 更新效率略高(无重复检查);查询效率与 Unique 基本一致 插入 / 更新效率略低(需额外检查唯一性);查询效率略优(叶子节点数据量少,查找更快)
适用场景 频繁查询、字段值可能重复的场景(如:商品分类、用户昵称、文章标签) 字段值唯一的场景(如:手机号、身份证号、用户名、订单号),需确保数据唯一性

关键补充:

  1. 主键索引是特殊的 Unique 索引:PRIMARY KEY 本质是「非空 + 唯一」的 Unique 索引(不允许 NULL 值),优先级高于普通 Unique 索引。
  2. 组合 Unique 索引:若创建 UNIQUE KEY (col1, col2),则约束「col1+col2 的组合值唯一」,而非单个字段唯一(比如 col1 可重复,但 col1+col2 不可重复)。
  3. 唯一性约束的本质:Unique 索引的核心作用是「保证数据唯一性」,查询优化是附加作用;而 Normal 索引的核心作用就是「加速查询」。

二、索引方法:BTree(默认) vs Hash

核心差异是 索引的存储结构和查询逻辑,直接决定了「哪些查询场景能生效」,MySQL 中最常用的是 BTree(实际是 B+Tree),Hash 仅适用于特定场景:
 
对比维度BTree(实际为 B+Tree)Hash 索引
存储结构 平衡多路查找树(B+Tree),数据按「字段值有序排列」,叶子节点串联成链表 哈希表结构,通过「字段值哈希计算」得到索引位置,数据无序
适用查询类型 支持所有查询场景:等值查询(=)、范围查询(>、<、BETWEEN)、排序(ORDER BY)、分组(GROUP BY)、前缀匹配(LIKE 'abc%') 仅支持 等值查询(=、<>、IN),不支持范围、排序、模糊查询(除精确匹配外均失效)
查询效率 等值查询:O (logn)(稳定高效);范围查询:O (logn + 扫描行数)(因有序,无需全表扫描) 理想情况:O (1)(直接通过哈希值定位);存在哈希冲突时:O (k)(k 为冲突数据量,冲突多则效率下降)
数据有序性 索引本身有序(叶子节点按字段值升序 / 降序排列) 索引无序(哈希值随机分布)
字段类型支持 支持所有字段类型(字符串、数字、日期等) 仅支持「能计算哈希值」的字段类型(数字、字符串等),不支持 blob、text 等类型
覆盖索引支持 支持(可直接从索引叶子节点获取查询字段,无需回表) 不支持(哈希索引仅存储「哈希值 + 行指针」,必须回表查询原始数据)
NULL 值处理 正常存储,支持 NULL 值查询 支持 NULL 值(哈希值统一处理),但同样仅支持等值查询
存储引擎支持 所有主流引擎(InnoDB、MyISAM、Memory)默认支持 仅 Memory 引擎默认支持;InnoDB 不支持手动创建 Hash 索引(仅内部自适应哈希索引,不可控)
适用场景 绝大多数业务场景(需范围查询、排序、模糊匹配) 仅内存数据库(Memory)+ 纯等值查询场景(如:缓存键值对查询、简单字典查询)

关键补充:

  1. B+Tree 是 MySQL 的默认选择:InnoDB 和 MyISAM 均默认使用 B+Tree 索引,因为它能适配业务中 99% 的查询场景(比如分页查询 LIMIT、范围筛选 price BETWEEN 100 AND 200、前缀模糊查询 name LIKE '张%')。
  2. Hash 索引的局限性:
    • 不支持范围查询:比如 id > 100 无法通过 Hash 索引查询(哈希值无序,无法确定范围);
    • 不支持排序:ORDER BY col 需全表排序(Hash 索引无序);
    • 哈希冲突问题:若多个字段值哈希后得到相同位置,需线性探测 / 链表解决,冲突多则效率接近全表扫描;
  3. InnoDB 的自适应哈希索引(AHI):InnoDB 会自动对频繁等值查询的 BTree 索引创建 Hash 索引(内存中),无需手动干预,目的是优化等值查询效率,但不可控(无法手动创建 / 删除)。

三、总结:如何选择?

  1. 索引类型(Normal/Unique):
    • 需保证字段值唯一 → 用 Unique(或主键索引);
    • 无需唯一性,仅需加速查询 → 用 Normal。
  2. 索引方法(BTree/Hash):
    • 绝大多数场景(需范围、排序、模糊查询) → 用默认的 BTree(无需手动指定);
    • 仅 Memory 引擎 + 纯等值查询 → 考虑 Hash 索引(极少用)。
 
最终组合示例:
 
  • 用户名(唯一 + 需查询)→ UNIQUE KEY idx_username (username)(BTree+Unique);
  • 商品价格(非唯一 + 需范围查询)→ KEY idx_price (price)(BTree+Normal);
  • 内存数据库中的字典表(纯等值查询)→ KEY idx_dict_key (dict_key) USING HASH(Hash+Normal)。

 

 

MySQL的 索引类型 normal、 unique 其实差不多,如果有limit 1这样的条件。

 

你说 Normal 索引的查询效率与 Unique 基本一致; 如果我在某字段创建了 Normal 索引,然后在这个字段上做where条件查询同时 limit 1,那么是不是意味着需要扫描它的全部索引, 那么速度也会比较慢吧, 如果是 unique, 那么不需要吧、效率就差比较多了吧 

-- 这里其实问错了, 本意是询问没有limit 1的情况

你的核心误解是 “Normal 索引加 LIMIT 1 需要扫描全部索引” —— 这其实是错的!不管是 Normal 还是 Unique 索引(默认都是 BTree 结构),WHERE 字段=xxx LIMIT 1 的查询逻辑都是 “快速定位到第一个匹配项,然后直接返回,不会扫描全部索引”,因此两者的查询效率几乎没有差距,远达不到 “差比较多” 的程度。

一、先理清核心逻辑:BTree 索引 + LIMIT 1 的查询过程(Normal 和 Unique 通用)

BTree 索引的本质是「有序的平衡树」,叶子节点按字段值排序且串联成链表。不管是 Normal 还是 Unique,执行 WHERE col=xxx LIMIT 1 时,查询流程完全一致:
 
  1. 从 BTree 的根节点开始,通过二分查找快速定位到「字段值 = xxx」的叶子节点(时间复杂度 O (logn),和索引大小无关,只和树的高度有关,通常 3-4 层);
  2. 找到第一个匹配的叶子节点后,因为有 LIMIT 1,直接返回该节点对应的行数据,停止后续所有扫描(不会继续查找后面是否有重复值,哪怕是 Normal 索引允许重复)。
 
举个例子:假设字段name是 Normal 索引,有 100 万条数据,其中 10 万条都是name='张三'。执行 WHERE name='张三' LIMIT 1 时,数据库找到第一个「name=' 张三 '」的叶子节点就直接返回,不会去扫剩下的 99999 个「张三」—— 这和 Unique 索引(只有 1 个「张三」)的查询过程完全一样,都是 “找到第一个就停”。

二、Normal 和 Unique 在「WHERE+LIMIT 1」场景下的效率差异:几乎可以忽略

两者的差异仅来自「Unique 索引的唯一性约束对索引结构的微小影响」,但对查询速度的影响极小:
 
对比点Normal 索引Unique 索引
定位第一个匹配项的速度 O (logn)(和 Unique 完全一致) O (logn)(和 Normal 完全一致)
停止条件 找到第一个匹配项,因 LIMIT 1 直接返回 找到第一个匹配项,因 Unique 约束确认无重复,直接返回
实际扫描量 1 个叶子节点(最多 2-3 个相邻节点,因 BTree 页存储多条数据) 1 个叶子节点(无需考虑后续重复,停止更 “果断”)
效率差异 几乎无差异,耗时差距在微秒级 略快,但人类感知不到(比如 0.1ms vs 0.09ms)
 
简单说:查询阶段的核心耗时是 “定位到第一个匹配项”(O (logn)),而两者在这一步完全一致;后续的 “停止逻辑” 差异对总耗时的影响微乎其微。

三、什么时候会出现明显效率差距?(几乎不涉及 LIMIT 1 场景)

只有当你的查询不满足 “快速定位第一个匹配项” 时,两者才可能有可感知的差距,但这种场景和LIMIT 1无关:
 
  1. 无 WHERE 条件,仅 LIMIT 1:比如 SELECT * FROM t LIMIT 1。此时 Normal 和 Unique 索引都用不上(无过滤条件),都走全表扫描(或主键索引扫描),效率完全一致;
  2. 查询重复值极多的字段,且不带 LIMIT 1:比如 SELECT * FROM t WHERE name='张三'(10 万条结果)。此时:
    • Normal 索引:需要扫描所有 10 万个「张三」对应的叶子节点(有序串联,扫描效率仍比全表高);
    • Unique 索引:因约束无重复,扫描 1 个节点就结束;
       
      这种场景下 Unique 确实快很多,但你加了 LIMIT 1,就屏蔽了这个差异;
  3. 组合索引场景:比如组合 Normal 索引 (col1, col2),查询 WHERE col1='a' LIMIT 1。同样是定位到第一个col1='a'的节点就返回,和组合 Unique 索引效率一致。

四、关键结论:不用纠结 “Normal+LIMIT 1” 的效率,核心看是否需要唯一性约束

  1. 查询效率层面:Normal索引+WHERE+LIMIT 1 和 Unique索引+WHERE+LIMIT 1 的效率几乎没有区别,都能快速定位并返回,不会扫描全部索引;
  2. 差异本质:Unique 索引的核心价值是「保证数据唯一性」(避免重复插入),而不是 “查询更快”—— 查询效率的微弱优势只是唯一性约束带来的 “附加福利”;
  3. 选择逻辑:
    • 若字段值必须唯一(如手机号、用户名)→ 用 Unique 索引(优先保证数据正确性,顺带略提查询效率);
    • 若字段值可重复(如商品分类、用户昵称)→ 用 Normal 索引(无需唯一性检查,插入 / 更新效率略高,查询 + LIMIT 1 完全够用)。
 
举个实际测试场景(InnoDB,100 万条数据):
 
  • Normal 索引 idx_name (name),查询 SELECT id FROM t WHERE name='张三' LIMIT 1 → 耗时 0.12ms;
  • Unique 索引 uk_name (name),相同查询 → 耗时 0.10ms;
     
    两者差距仅 0.02ms,完全不影响业务性能。真正影响效率的是 “是否建索引”“索引是否被命中”,而不是 Normal 和 Unique 的选择。

 

你的质疑非常关键!核心结论先明确:你说的 “查询到一个就返回” 是对的,但 “全表扫描” 的定义需要澄清 —— 这里的 “全表扫描”≠扫描所有数据,而是 “扫描表的主数据载体(聚集索引 / 表文件)”,且会在拿到第一条数据后立即停止,不会扫完整张表。
 
之前的表述不够精准,导致了误解,现在详细拆解:

一、先纠正 “全表扫描” 的误区:MySQL 中 “全表扫描(Full Table Scan)” 的真实含义

“全表扫描” 不是 “必须扫描表中所有行”,而是指:
 
  • 数据库没有使用二级索引(Normal/Unique 都是二级索引),而是直接扫描表的「主数据载体」:
    • InnoDB:扫描「聚集索引」(主键索引,表数据本身就是按聚集索引组织的,叶子节点就是完整行数据);
    • MyISAM:扫描「表文件本身」(按数据插入顺序存储的堆表)。
  • 扫描过程中,只要满足条件(这里是 “拿到 1 行数据”),就会立即停止扫描,不会继续往后找。
 
简单说:SELECT * FROM t LIMIT 1 的 “全表扫描” 是「短路扫描」—— 只扫 1 行就停,不是扫完整张表。

二、为什么二级索引(Normal/Unique)用不上?

核心原因是 SELECT * 需要获取「整行数据」,而二级索引(不管 Normal 还是 Unique)的结构是:索引字段值 → 主键ID(InnoDB),无法直接存储整行数据。
 
如果强行用二级索引查询,流程是:
 
  1. 扫描二级索引,找到第一条数据(因为二级索引有序,找第一条很快);
  2. 拿到主键 ID 后,再去「聚集索引」中查完整行数据(这一步叫 “回表”);
  3. 因为 LIMIT 1,返回数据,停止操作。
 
而直接扫描「聚集索引 / 表文件」的流程是:
 
  1. 从聚集索引 / 表文件的第一条数据开始读;
  2. 读到第一条就直接返回,停止操作。
 
对比下来,“直接扫主数据载体” 比 “走二级索引 + 回表” 少一步,效率更高。所以 MySQL 优化器会自动选择前者,放弃二级索引 —— 不是二级索引不能用,而是用了反而更慢,优化器会规避这种低效路径。

三、不同存储引擎的实际执行逻辑(验证 “只扫 1 行”)

1. InnoDB(有聚集索引)

  • 执行 SELECT * FROM t LIMIT 1 时,优化器会选择扫描「聚集索引」(主键索引);
  • 聚集索引是有序的(按主键排序),数据库从聚集索引的最左叶子节点(第一条数据)开始读取,拿到 1 行后立即终止扫描,不会继续往后遍历;
  • 耗时极短(通常微秒级),和 “扫全表”(遍历所有数据)完全是两回事。

2. MyISAM(无聚集索引,堆表)

  • 表数据按插入顺序存储在文件中,执行查询时,从文件开头读第一行数据,拿到后立即停止;
  • 同样只扫 1 行,不会读取整个文件。

四、特殊情况:什么时候会走二级索引?(和 LIMIT 1 无关,和查询字段有关)

如果查询的字段全部包含在二级索引中(即 “覆盖索引”),优化器会选择走二级索引,因为无需回表,效率和扫聚集索引差不多:
 
sql
 
 
-- 假设二级索引 idx_name (name),查询字段只有 name 和 id(id是主键,会自动包含在二级索引中)
SELECT name, id FROM t LIMIT 1;
 
 
此时:
 
  • 二级索引的叶子节点包含 name + id,无需回表,优化器会走二级索引,读取第一条数据后停止;
  • 但这和 “是否 LIMIT 1” 无关,核心是 “覆盖索引”;如果还是 SELECT *,即使 LIMIT 1,仍会走聚集索引 / 表文件。

五、总结:澄清 3 个关键认知

  1. 你的核心判断是对的:LIMIT 1 会在拿到第一条数据后立即返回,不会扫描整张表;
  2. “全表扫描” 的精准定义:是 “扫描表的主数据载体(聚集索引 / 表文件)”,而非 “扫描所有数据”;带 LIMIT 1 的全表扫描是「短路扫描」,仅读 1 行;
  3. 二级索引(Normal/Unique)用不上的原因:SELECT * 需要整行数据,走二级索引需回表,效率低于直接扫主数据载体,优化器会自动放弃。
 
简单验证方法(MySQL 中执行):
 
用 EXPLAIN 查看执行计划,会发现 type: ALL(表示全表扫描),但 Rows 字段会显示 “预估扫描行数”(通常是 1),Extra 无 “Using filesort”“Using temporary”,说明仅扫描 1 行就停止:
 
sql
 
 
EXPLAIN SELECT * FROM t LIMIT 1;
-- 结果示例:
-- id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra
-- 1  | SIMPLE      | t     | ALL  | NULL          | NULL | NULL    | NULL | 1    |
 
 
这里的 rows: 1 就是优化器预估的扫描行数,证明不会扫全表。
 
最终结论:无 WHERE 仅 LIMIT 1 时,确实不用二级索引(Normal/Unique 都不用),但 “全表扫描” 是短路的,只扫 1 行就返回,效率极高,和 “扫完整张表” 完全不是一个概念。你担心的 “扫全表变慢” 是不存在的~
 
 
总结:
BTree(默认) vs Hash 是索引的存储结构 ; Normal(普通索引) vs Unique(唯一索引) 是「索引的约束类型」
 
 
 
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/973442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

精读 GitHub - servo 浏览器(一)

精读 GitHub - servo 浏览器(一)一、简介项目地址:https://github.com/servo/servo这一期的精读 GitHub 系列是 servo 浏览器,我们将从源码的角度去拆解 servo 浏览器,逐步厘清整个浏览器的工作原理。 servo 是一…

50040_基于微信小程序的项目管理系统

1.项目包含 项目源码、项目文档、数据库脚本、软件工具等资料; 带你从零开始部署运行本套系统。 2.项目介绍 在信息化浪潮的推动下,以互联网和信息技术为代表的现代科技正深刻重塑人类社会的发展格局,这种变革使得基…

hyper v linux

你提到的 "Hyper-V Linux" 可能是指在 Linux 系统上使用 Hyper-V 技术进行虚拟化。Hyper-V 是 Microsoft 提供的虚拟化平台,主要用于 Windows 操作系统。然而,Linux 系统本身并不直接支持 Hyper-V 虚拟化技…

hyper for linux

“Hyper for Linux” 是一个基于 Electron 的轻量级跨平台桌面应用程序,主要用于在 Linux 系统上运行 Hyper(一个基于 Node.js 的高性能 Web 服务器)。Hyper 是一个高性能的 Web 服务器,常用于开发和测试 Web 应用…

https linux

您提到的“https linux”可能是指与 Linux 系统 相关的 HTTPS 服务 或 HTTPS 安全协议 的使用。以下是一些与 Linux 系统和 HTTPS 相关的常见问题和解决方案,供您参考:1. 如何在 Linux 上安装 HTTPS 服务?常用 HTTP…

页面

在word里面,逻辑单位是1页文档是A4尺寸单面打印的话,3页word,就需要3张A4纸双面打印的话,4页word,就需要2张A4纸,正反文档是A4尺寸需要打印到A3纸4页A4 word, 双面打印 1张A3纸的2个面2页A4 word ,单面打印 …

Trick——数据结构

Part1 你真的以为树状数组只能止步于区修区查了吗? 实际上有这样一种特殊的最值:前缀最值查询。 代码: struct BIT{int tr[N];inline int lowbit(int x){ return (x&(-x)); }void add(int x,int val){for(int i…

锂矿及其投资机会

锂矿公司 锂辉石矿 天齐锂业 矿产资源介绍:控股澳大利亚泰利森公司,手握全球最大硬岩锂矿 —— 格林布什锂辉石矿,权益储量达 1614 万吨 LCE,同时还布局了四川措拉锂辉石矿,资源自给率达 100%,其电池级氢氧化锂技…

电梯调度迭代编程作业复盘:从问题剖析到能力进阶

一、对三次电梯调度题目集的整体认知 (一)知识点覆盖与考察重点 三次电梯调度题目集聚焦面向对象编程核心知识点与工程化开发能力,核心考察内容可归纳为三类: 设计原则:核心是单一职责原则(SRP)。从第一次的 “…

MORL | Envelope Q-Learning:有收敛性保证的 MORL 算法

EQL 将单目标的 bellman 算子拓展到多目标 RL 上,并复刻了 value iteration 的收敛性保证。论文标题:A Generalized Algorithm for Multi-Objective Reinforcement Learning and Policy Adaptatio。 NeurIPS 2019。也…

获深圳人才集团认可!「张张讲AI」AI资讯公众号解读AI动态,讲师提供定制化咨询

获深圳人才集团认可!「张张讲AI」AI资讯公众号解读AI动态,讲师提供定制化咨询在人工智能快速发展的时代,各行各业都在努力融入这一新兴技术,以谋求更好的发展。而张张讲AI作为人工智能应用培训领域的重要力量,凭借…

多重背包 二进制拆分这个向左移动以为是2也是被我写出来了

include <bits/stdc++.h> using namespace std; int dp[105];int v[2000];int w[2000]; int main() { int c;cin>>c; while(c--) { int n,m;cin>>n>>m; memset(v,0,sizeof(v)); memset(w,0,si…

NOIP2025

NOIP2025前情提要:CSP-S 2025 \(100+80+50+24\)。。

why exams are bad

"i know many things, but professors just check the things I dont know!" it will hurt buddys confidence, let one think hes a loser. how much people understand Hebrew, Chinese or Japanese? how…

若依框架源码—2

若依框架——每一个模块的解读 模块分类模块图首先我们可以看到一共有六个模块 通过注释分析,我们可以得出,admin 模块 后端管理模块,项目的启动入口其中还包含了项目的配置文件common 模块 后端通用模块,通用的工…

http linux

您提到的“http linux”可能是指与 HTTP 相关的 Linux 操作系统相关的问题,或者是想了解在 Linux 系统中如何处理 HTTP 请求或相关服务。请提供更多具体问题或需求,以便我为您提供准确的 Linux 命令或脚本建议。例如…

html空间能用于表单吗

HTML空间(HTML Space)可以用于表单。HTML空间主要用于在HTML文档中插入不可见的特殊字符,这些字符在浏览器中不会显示,但可以在源代码中使用。在表单提交时,HTML空间中的字符也会被一起提交。因此,如果需要在表单…

html空间能用于布局吗

HTML空间本身并不直接用于布局,但HTML元素和CSS样式可以用于创建和控制网页的布局。HTML提供了页面结构,而CSS则负责样式和布局。以下是HTML和CSS在网页布局中的具体应用: HTML用于布局表格布局:虽然不推荐用于布局…

01 背包不可达一维

一维的一定要从头遍历进行分类 二维可以从f[i]因为他在继承新值 include <bits/stdc++.h> using namespace std; int j[1005]; int f[1005]; int dp[1005]; int main() { int m, n; while (cin >> m >…

数据结构——BF算法 - 指南

数据结构——BF算法 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", …