当前位置: 首页 > news >正文

MySQL问题4

MySQL中varchar和char的区别

在 MySQL 中,VARCHARCHAR 都是用于存储字符串类型的字段,但它们在存储方式、性能、适用场景等方面存在明显区别:


1. 存储方式

类型说明
CHAR(n)定长字符串,始终占用固定 n 个字符空间。不足的会自动在右侧补空格(存储时),查询时会自动去除补空格。
VARCHAR(n)变长字符串,只占用实际字符长度 + 1 或 2 个字节(记录长度信息)

举例:

CHAR(10): 存 'abc',存储为 'abc       '(右侧补7个空格)
VARCHAR(10): 存 'abc',只占 3 + 1 = 4 个字节

2. 性能对比

特性CHARVARCHAR
读取速度较快(定长,容易定位)略慢(需读取长度信息)
更新性能稳定(定长不易产生碎片)大量更新可能导致行迁移和碎片
空间占用多(始终固定长度)少(根据实际长度变化)

CHAR 读取更快,但除非数据长度始终一致,否则它占用空间较大。


3. 使用场景推荐

场景推荐类型
固定长度,如身份证号、邮编、MD5、UUIDCHAR
可变长度,如名字、地址、备注等VARCHAR

4. 其他注意事项

  • 最大长度限制

    • CHAR 最多 255 个字符。
    • VARCHAR 最多 65535 字节(注意字符集影响,如 utf8 每字符占 3 字节)。
  • 行格式限制

    • InnoDB 表中,如果 VARCHAR 太长,可能会被拆分存储到“溢出页”。

口诀:

「定长用 CHAR,变长用 VARCHAR;空间选 VARCHAR,速度选 CHAR。」


MySQL中count()、count(1)和count(字段名)的区别

在 MySQL 中,COUNT()COUNT(1)COUNT(字段名) 都是用于统计行数的聚合函数,但它们在统计逻辑、NULL 处理、性能优化等方面存在区别。

1 、三者区别

表达式含义是否统计 NULL 行典型用途
COUNT(*)统计所有行数(包括 NULL)表行数统计
COUNT(1)统计所有行数(包括 NULL),效果等同于 COUNT(*)和 COUNT(*) 一样
COUNT(字段名)统计字段值不为 NULL 的行数判断某列有多少有效值

示例:

假设有一张表 users

idnameage
1Alice15
2NULL25
3CharlieNULL
4NULLNULL
1. SELECT COUNT(*) FROM users;

返回 4,统计全部行。

2. SELECT COUNT(1) FROM users;

返回 4,和 COUNT(*) 一样,1只是个常量

3. SELECT COUNT(name) FROM users;

返回 2,因为只有两行 name 不是 NULL。

4. SELECT COUNT(age) FROM users;

返回 2,同样只统计非 NULL 的 age


2、性能区别

  • COUNT(*)最推荐使用的统计行数方式:

    • MySQL 优化器会做特别优化,不实际读取列,直接走统计信息。
  • COUNT(1) 理论上和 COUNT(*) 等价,区别不大,但没有 COUNT(*) 优化彻底。

  • COUNT(字段名) 性能较慢,因为需要判断字段是否为 NULL

用途推荐用法
统计表的总行数COUNT(*)
统计某列的非空数量COUNT(字段名)
代替 COUNT(*)(不推荐)COUNT(1)

区别:

  1. COUNT(*):最全、最快,连 NULL 也算。
  2. COUNT(1):等价于 COUNT(*),但没优化优势。
  3. COUNT(字段):只数非 NULL 的字段行。

MySQL的B+树中查询数据的全过程

假设我们有以下索引结构(id 是主键):

          [30 | 60]/    |    \[10 20] [40 50] [70 80 90] ← 叶子节点,存数据
  • 根节点 [30, 60]:索引 key,不存数据
  • 叶子节点:[10,20], [40,50], [70,80,90] 存储完整行数据(聚簇索引)
  • 每个节点就是一页(Page),约16KB

1、查询过程(以查询 id = 70 为例)

步骤一:从根节点开始搜索

  • 根节点 key 为 [30, 60]
  • 70 > 60 → 选择第三个子节点:[70, 80, 90]

步骤二:进入叶子节点

  • 叶子节点是 [70, 80, 90]
  • 在叶子节点内部做二分查找或顺序查找
  • 找到 id=70 对应的整行数据(聚簇索引)

查找完成!


2、全过程总结(图解)

           +-------------+|  30   60    |   ← 根节点 (非叶子)+-------------+/     |      \+----------+ +------+---------+|10 20 ... | |40 50 ...| 70 80 90 ← 叶子节点+----------+ +------+---------+
  • 查询 id=45

    • 根节点:[30,60] → 45 位于中间 → 走中间分支
    • 进入 [40,50] 节点 → 找到 45 或返回不存在

示例:B+树结构示意图

以一个主键索引为例(InnoDB 聚簇索引),建表如下:

CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(20)
);

假设表中数据如下(id 是主键):

id: 10, 20, 30, 40, 50, 60, 70, 80, 90

经过 B+ 树组织后,大概结构如下:

                             [40]/       \[10, 20, 30]       [50, 60, 70] --------> [80, 90](页1)              (页2)                    (页3)
  • [] 表示一个页(Page),每页约16KB,包含多个 key
  • 叶子节点之间通过链表相连(→),支持范围查找
  • 中间节点只存索引 key,不存数据
  • 叶子节点存完整行数据(id, name)

查询过程可视化:查找 id = 70

Step 1:从根节点开始
┌───────────────┐
│     [40]      │ ← 根节点(非叶子)
└───────────────┘│└── id > 40,向右走Step 2:进入右子树
┌────────────────────┐
│   [50, 60, 70]      │ ← 叶子节点,页2
└────────────────────┘Step 3:在页2中顺序查找找到了 id = 70,对应整行数据 name = 'Tom'

查询完成,最多访问两页内存/磁盘页。


范围查询过程:查找 id BETWEEN 60 AND 85

Step 1:从根节点 [40] 开始,id > 40 → 右子树Step 2:访问页2 [50, 60, 70] → 拿到 60, 70Step 3:顺着链表 → 页3 [80, 90] → 拿到 80,停止最终结果:60, 70, 80

特性可视化图中的体现
多路平衡根节点拆成多个范围,指向多个子页
快速查找每层只需一次判断(最多 2~4 层)
范围查找快叶子节点链表结构,顺着链表走
聚簇存储叶子节点含完整行,不用回表

文章转载自:

http://gXOrmkC3.tymwx.cn
http://02dDab2f.tymwx.cn
http://cga9LpCh.tymwx.cn
http://sOrsssVF.tymwx.cn
http://fb8hoHbK.tymwx.cn
http://HWqNHzAt.tymwx.cn
http://15BJR3Xk.tymwx.cn
http://yo5z6OJp.tymwx.cn
http://iIPUUulO.tymwx.cn
http://eWncDhMn.tymwx.cn
http://dAOS9gyE.tymwx.cn
http://6byQVkyB.tymwx.cn
http://HnH79958.tymwx.cn
http://oeGEPrc2.tymwx.cn
http://86sJatO6.tymwx.cn
http://uUTicooa.tymwx.cn
http://h5Xtnrx4.tymwx.cn
http://0xongdBU.tymwx.cn
http://zBOPDl6C.tymwx.cn
http://hA6z2WLD.tymwx.cn
http://0ij6bbrO.tymwx.cn
http://zdo7fdHd.tymwx.cn
http://cdbiqgDF.tymwx.cn
http://zYfP68TX.tymwx.cn
http://RKosRpWS.tymwx.cn
http://SMLwFE9e.tymwx.cn
http://mt9EYJ2J.tymwx.cn
http://1S72gSKM.tymwx.cn
http://iCLv0IYJ.tymwx.cn
http://KgsHyIGU.tymwx.cn
http://www.dtcms.com/a/368591.html

相关文章:

  • PHY的自适应协商简析
  • MySQL InnoDB 的锁机制
  • 海盗王64位dx9客户端修改篇之五
  • 官宣:Apache Cloudberry (Incubating) 2.0.0 发布!
  • SpringBoot 中 ThreadLocal 的妙用:原理、实战与避坑指南
  • Unity Hub 创建支持 Android iOS 的项目教程
  • LangGraph节点完整组成与要求详解
  • 【Qt开发】按钮类控件(三)-> QCheckBox
  • mcp_clickhouse代码学习
  • Spring Boot 源码深度解析:揭秘自动化配置的魔法
  • 指定端口-SSH连接的目标(告别 22 端口暴力破解)
  • PNPM库离线安装方案
  • MacOS 15.6 编译SDL3 Android平台多架构so库
  • 鸿蒙:获取UIContext实例的方法
  • 计算机原理-计算机操作系统-硬盘缓存、断电丢数据篇
  • 普通键盘在MacOS上如何使用快捷键
  • 分布式专题——1.1 Redis单机、主从、哨兵、集群部署
  • Redis 持久化机制:RDB 快照深度解析
  • 在选择iOS代签服务前,你必须了解的三大安全风险
  • MCP驱动企业微信智能中枢:企业级机器人服务构建全攻略
  • 期望阻抗模型中的相互作用力方向是机器人施加给环境的还是环境施加给机器人的?
  • bc 命令详解:Linux 下的任意精度计算器
  • B.50.10.06-NoSQL数据库与电商应用
  • 【前端教程】JavaScript DOM 操作实战案例详解
  • 假设一个算术表达式中包含圆括号、方括号和花括号3种类型的括号,编写一个算法来判别,表达式中的括号是否配对,以字符“\0“作为算术表达式的结束符
  • 【数学建模】数据预处理入门:从理论到动手操作
  • 机器学习(七)决策树-分类
  • 汽车软件研发智能化:AI在CI/CD中的实践
  • 有序数组,距离目标最近的k个数 二分查找
  • 函数式组件父子ref通讯