mysql-笔记一

一、数值类型

1. 整数类型(INTEGER)

类型 存储空间 有符号范围 无符号范围(UNSIGNED) 用途
TINYINT 1字节 -128 ~ 127 0 ~ 255 年龄、状态、性别、小枚举
SMALLINT 2字节 -32768 ~ 32767 0 ~ 65535 评分、库存量、小范围数值
MEDIUMINT 3字节 -8388608 ~ 8388607 0 ~ 16777215 中等范围数值(如粉丝数)
INT / INTEGER 4字节 -2147483648 ~ 2147483647 0 ~ 4294967295 主键id、数量(最常用)
BIGINT 8字节 -9223372036854775808 ~ 9223372036854775807 0 ~ 18446744073709551615 超大id、订单号、时间戳(毫秒)

属性说明:

sql 复制代码
-- UNSIGNED:无符号,不能存负数(范围翻倍)
age TINYINT UNSIGNED  -- 0~255

-- ZEROFILL:不足位数补0(自动加UNSIGNED)
id INT(5) ZEROFILL  -- 存1显示00001

-- 括号内数字(如 INT(11)):不影响范围,只影响显示宽度(配合ZEROFILL)

2. 浮点类型(非精确数值,有精度丢失风险)

类型 存储空间 有符号范围 无符号范围 精度 用途
FLOAT 4字节 ±1.175494351E-38 ~ ±3.402823466E+38 0 ~ ±3.402823466E+38 约7位小数 科学计算、温度、百分比(不需要精确的场景)
FLOAT(M,D) 4字节 取决于M,D 取决于M,D 约7位小数 指定小数位数的浮点数(不推荐)
DOUBLE 8字节 ±2.2250738585072014E-308 ~ ±1.7976931348623157E+308 0 ~ ±1.7976931348623157E+308 约15位小数 科学计算、高精度浮点运算
DOUBLE(M,D) 8字节 取决于M,D 取决于M,D 约15位小数 指定小数位数的双精度(不推荐)
REAL 8字节 同DOUBLE 同DOUBLE 约15位小数 DOUBLE的同义词(取决于MySQL设置)
FLOAT(p) 变长 取决于p 取决于p 取决于p p=0~24用FLOAT,p=25~53用DOUBLE

参数说明:

  • M:总位数(最大255)
  • D:小数位数(最大30)
  • p:精度位数(0~53)

⚠️ 核心问题:精度丢失

浮点数采用二进制存储,某些十进制小数无法精确表示:

sql 复制代码
-- ❌ 浮点数计算会出错
SELECT 0.1 + 0.2;  
-- 结果:0.30000000000000004(不是 0.3!)

-- ❌ 比较也会出问题
SELECT 0.1 = 0.1;  -- 看起来没问题
SELECT 0.1 + 0.2 = 0.3;  -- 结果是 0(false)!

-- ✅ 用DECIMAL就精确
SELECT CAST(0.1 AS DECIMAL(10,2)) + CAST(0.2 AS DECIMAL(10,2));
-- 结果:0.30

二、字符串类型

1. 字符类型(最常用)

类型 最大长度 存储空间 特点 用途
CHAR(N) 255字符 固定N字节 定长、性能略好、浪费空间 手机号(11)、身份证(18)、MD5(32)、固定编码
VARCHAR(N) 65535字符 实际长度 + 1~2字节 变长、最常用、节省空间 姓名、标题、地址、描述、邮箱
TINYTEXT 255字符 实际长度 + 1字节 短文本、有长度前缀 极短内容(很少用,已被VARCHAR替代)
TEXT 65535字符 实际长度 + 2字节 长文本、有长度前缀 文章内容、备注、评论、富文本
MEDIUMTEXT 16777215字符(约16MB) 实际长度 + 3字节 中等长文本 日志、JSON数据、序列化数据
LONGTEXT 4294967295字符(约4GB) 实际长度 + 4字节 超长文本 全文、大数据JSON、大型文档

存储空间计算(UTF-8编码):

字符类型 存储字节数
英文字母/数字 1字节
中文字符 3字节(UTF-8)
Emoji表情 4字节
特殊符号 1~4字节
sql 复制代码
-- 示例:VARCHAR(50) 在 UTF-8 下
-- 存 'hello' → 5字节 + 1字节前缀 = 6字节
-- 存 '你好' → 6字节 + 1字节前缀 = 7字节
-- 存 '😊' → 4字节 + 1字节前缀 = 5字节

三、日期时间类型

1. 完整类型列表

类型 格式 范围 存储空间 零值 用途
DATE 'YYYY-MM-DD' '1000-01-01' ~ '9999-12-31' 3字节 '0000-00-00' 生日、入职日期、合同开始日
TIME 'HH:MM:SS' '-838:59:59' ~ '838:59:59' 3字节 '00:00:00' 上班时间、时长、倒计时
DATETIME 'YYYY-MM-DD HH:MM:SS' '1000-01-01 00:00:00' ~ '9999-12-31 23:59:59' 8字节 '0000-00-00 00:00:00' 创建时间、更新时间(最常用)
TIMESTAMP 'YYYY-MM-DD HH:MM:SS' '1970-01-01 00:00:01' UTC ~ '2038-01-19 03:14:07' UTC 4字节 '0000-00-00 00:00:00' 跨时区系统、日志时间
YEAR 'YYYY' 1901 ~ 2155 1字节 0000 毕业年份、成立年份
TIMESTAMP(6) 带微秒 同上 7字节 '0000-00-00 00:00:00.000000' 高精度时间(需微秒级)
DATETIME(6) 带微秒 同上 8字节 '0000-00-00 00:00:00.000000' 高精度时间(带微秒)

2. DATE 类型(只有日期)

sql 复制代码
-- 常见格式
birthday DATE COMMENT '生日'

-- 插入数据(多种格式)
INSERT INTO users (birthday) VALUES ('1990-05-15');
INSERT INTO users (birthday) VALUES ('1990/05/15');
INSERT INTO users (birthday) VALUES ('19900515');
INSERT INTO users (birthday) VALUES (NOW());  -- 当前日期

-- 常用函数
SELECT YEAR(birthday) FROM users;   -- 提取年份
SELECT MONTH(birthday) FROM users;  -- 提取月份
SELECT DAY(birthday) FROM users;    -- 提取日
SELECT WEEKDAY(birthday) FROM users; -- 星期几(0=周一)
SELECT DATE_ADD(birthday, INTERVAL 1 YEAR); -- 加1年
SELECT DATEDIFF(NOW(), birthday) / 365 AS age; -- 计算年龄

四、表基本命令

  • 查看表数据库表
sql 复制代码
SHOW TABLES
  • 创建表
sql 复制代码
CREATE TABLE users (
    `id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    `name` VARCHAR(50) NOT NULL COMMENT '姓名',
    `age` TINYINT UNSIGNED DEFAULT 22 COMMENT '年龄',
    `salary` DECIMAL(10,2) COMMENT '工资(10位总长,2位小数)',
    `created_time` DATETIME DEFAULT NOW() COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  • 删除表
sql 复制代码
DROP TABLE users
  • 查看建表语句
sql 复制代码
SHOW CREATE TABLE users
  • 增、删、改、查
sql 复制代码
-- 插入
INSERT INTO users (name, age, salary) VALUES ('张三', 25, 8000.00);

-- 查询(最常用)
SELECT * FROM users WHERE age > 20 ORDER BY id DESC LIMIT 10;

-- 更新(务必加WHERE)
UPDATE users SET salary = 9000.00 WHERE id = 1;

-- 删除(务必加WHERE)
DELETE FROM users WHERE id = 1;
  • join链接以及外键
sql 复制代码
-- 用户表(users)
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
    name VARCHAR(50) NOT NULL COMMENT '姓名',
    age TINYINT UNSIGNED DEFAULT 0 COMMENT '年龄',
    created_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';

-- 订单表(orders)
CREATE TABLE orders (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
    order_id VARCHAR(32) NOT NULL COMMENT '订单号(业务唯一)',
    user_id INT NOT NULL COMMENT '用户ID',
    create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间(毫秒精度)',
    order_json JSON DEFAULT NULL COMMENT '订单扩展信息(JSON格式)',
    -- 索引
    UNIQUE KEY uk_order_id (order_id),
    KEY idx_user_id (user_id),
    KEY idx_create_time_desc (create_time DESC),
    -- 外键约束
    CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单表';


-- 1. 插入用户
INSERT INTO users (name, age) VALUES ('张三', 25), ('李四', 30), ('王五', 28);

-- 2. 插入订单(user_id 必须存在于 users 表)
INSERT INTO orders (order_id, user_id, order_json) VALUES
('ORD20260724001', 1, '{"product":"手机","price":2999.00}'),
('ORD20260724002', 1, '{"product":"耳机","price":399.00}'),
('ORD20260724003', 2, '{"product":"电脑","price":5999.00}');

-- 3. 查询订单及用户信息(连表查询)
-- 内链接
INNER JOIN
-- 左链接
LEFT JOIN
-- 右链接
RIGHT JOIN
SELECT 
    o.order_id,
    o.create_time,
    u.name AS user_name,
    u.age AS user_age,
    o.order_json
FROM orders o
LEFT  JOIN users u ON o.user_id = u.id
ORDER BY o.create_time DESC;

五、索引


索引是帮助 MySQL 高效获取数据的数据结构,类似于书的目录。

核心作用:

  • ✅ 大幅提升查询速度(从全表扫描 O(n) 变成 B+Tree 查询 O(log n))
  • ❌ 占用额外存储空间
  • ❌ 降低插入/更新/删除的速度(需要同步维护索引)

1. 按功能分类

索引类型 关键字 允许重复值 允许NULL 每表数量 用途
普通索引 INDEX / KEY ✅ 允许 ✅ 允许 多个 单纯加速查询
唯一索引 UNIQUE INDEX ❌ 不允许 ✅ 允许(只能1个NULL) 多个 加速 + 唯一约束
主键索引 PRIMARY KEY ❌ 不允许 ❌ 不允许 1个 加速 + 唯一 + 非空
全文索引 FULLTEXT INDEX ✅ 允许 ✅ 允许 多个 全文搜索(MyISAM/InnoDB 5.6+)
空间索引 SPATIAL INDEX ❌ 不允许 ❌ 不允许 多个 GIS地理信息查询

2. 按字段数量分类

索引类型 说明 最左匹配
单列索引 只建在1个字段上 不存在
联合索引(复合索引) 建在多个字段上,如 (age, salary) ✅ 必须遵守
覆盖索引 查询的所有字段都在索引中,无需回表 不涉及

3. 按存储结构分类

索引类型 底层结构 特点
B-Tree索引(默认) B+Tree 等值查询、范围查询(>、<、BETWEEN)都很快
Hash索引(极少用) 哈希表 等值查询极快,但不支持范围查询(Memory引擎专用)
R-Tree索引 R-Tree 空间索引(GIS地理信息)

4.索引操作命令

sql 复制代码
-- 建表时创建
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50),
    age TINYINT,
    salary DECIMAL(10,2),
    email VARCHAR(100),
    -- 普通索引
    INDEX idx_name (name),
    -- 唯一索引
    UNIQUE INDEX idx_email (email),
    -- 联合索引
    INDEX idx_age_salary (age, salary)
);

-- 建表后添加(方式1)
CREATE INDEX idx_name ON users(name);

-- 建表后添加(方式2,更灵活)
ALTER TABLE users ADD INDEX idx_name (name);

-- 添加唯一索引
CREATE UNIQUE INDEX idx_email ON users(email);
ALTER TABLE users ADD UNIQUE INDEX idx_email (email);

-- 添加全文索引(MySQL 5.6+ InnoDB支持)
CREATE FULLTEXT INDEX idx_content ON articles(content);
ALTER TABLE articles ADD FULLTEXT INDEX idx_content (content);

-- 添加联合索引
CREATE INDEX idx_age_salary ON users(age, salary);

-- 添加前缀索引(针对长字符串,节省空间)
CREATE INDEX idx_name_prefix ON users(name(10));  -- 只取前10个字符

5.索引失效

索引失效 = MySQL 执行查询时,没有使用你创建的索引 ,而是进行全表扫描(type = ALL)。

场景1:LIKE 以 % 开头

错误写法(索引失效):

sql 复制代码
SELECT * FROM users WHERE name LIKE '%张三%';
SELECT * FROM users WHERE name LIKE '%张三';

正确写法(索引生效):

sql 复制代码
SELECT * FROM users WHERE name LIKE '张三%';

原因: B+Tree 索引从左到右匹配,% 开头无法确定起始位置,只能全表扫描。

场景2:类型隐式转换

错误写法(索引失效):

sql 复制代码
-- phone 是 VARCHAR 类型
SELECT * FROM users WHERE phone = 13800138000;

正确写法(索引生效):

sql 复制代码
SELECT * FROM users WHERE phone = '13800138000';

原因: 等价于 CAST(phone AS INT) = 13800138000,对索引列用了函数。

场景3:对索引列使用函数

错误写法(索引失效):

sql 复制代码
SELECT * FROM users WHERE DATE(created_time) = '2026-07-24'; 
SELECT * FROM users WHERE YEAR(created_time) = 2026; 
SELECT * FROM users WHERE UPPER(name) = 'ZHANG';

正确写法(索引生效):

sql 复制代码
SELECT * FROM users WHERE created_time >= '2026-07-24' AND created_time < '2026-07-25'; 
SELECT * FROM users WHERE name = 'ZHANG';

原因: 对索引列使用函数,MySQL 无法利用索引的有序性。

场景4:OR 连接(必须所有字段都有索引)

错误写法(索引失效):

sql 复制代码
-- age 有索引,但 name 没有索引 
SELECT * FROM users WHERE age = 25 OR name = '张三';

正确写法(索引生效):

sql 复制代码
-- 方案1:用 UNION 
SELECT * FROM users WHERE age = 25 UNION SELECT * FROM users WHERE name = '张三';  
-- 方案2:给 name 也建索引 
CREATE INDEX idx_name ON users(name); 
SELECT * FROM users WHERE age = 25 OR name = '张三';

原因: OR 条件中只要有 1 个字段没有索引,整个查询就走全表扫描。


场景5:联合索引违反最左匹配

错误写法(索引失效):

sql 复制代码
-- 假设联合索引是 (age, salary, name)  
-- 跳过了 age,索引失效 
SELECT * FROM users WHERE salary = 8000; 
SELECT * FROM users WHERE name = '张三'; 
SELECT * FROM users WHERE salary = 8000 AND name = '张三';

正确写法(索引生效):

sql 复制代码
-- 从最左列 age 开始匹配 
SELECT * FROM users WHERE age = 25; 
SELECT * FROM users WHERE age = 25 AND salary = 8000; 
SELECT * FROM users WHERE age = 25 AND salary = 8000 AND name = '张三';

原因: 联合索引必须从索引的最左列开始匹配,不能跳过。


场景6:范围查询右侧截断(联合索引)

错误写法(索引失效):

sql 复制代码
-- 假设联合索引是 (age, salary, name)  
-- age 等值 → salary 范围 → name 失效(范围查询右侧截断) 
SELECT * FROM users WHERE age = 25 AND salary > 8000 AND name = '张三';

正确写法(索引生效):

sql 复制代码
-- 调整索引顺序:等值查询放前面,范围查询放后面 
CREATE INDEX idx_age_name_salary ON users(age, name, salary);  
-- 三个字段都能用上 
SELECT * FROM users WHERE age = 25 AND name = '张三' AND salary > 8000;

原因: 联合索引遇到 ><BETWEENLIKE 后,右侧的索引列会失效。


场景7:使用 != 或 <>

错误写法(索引失效):

sql 复制代码
SELECT * FROM users WHERE age != 25;
SELECT * FROM users WHERE age <> 25;

正确写法(索引生效):

sql 复制代码
SELECT * FROM users WHERE age < 25 OR age > 25;

原因: !=<> 无法利用索引的有序性,大多数情况全表扫描。


场景8:使用 NOT IN

错误写法(索引失效):

sql 复制代码
SELECT * FROM users WHERE age NOT IN (25, 30, 35);

正确写法(索引生效):

sql 复制代码
-- 方案1:用 NOT EXISTS 
SELECT * FROM users u1  
              WHERE NOT EXISTS (  
              SELECT 1 FROM users u2   
              WHERE u2.age IN (25, 30, 35) AND u2.id = u1.id 
);  
-- 方案2:用 LEFT JOIN + IS NULL
SELECT u1.* FROM users u1 
LEFT JOIN users u2 ON u1.id = u2.id AND u2.age IN (25, 30, 35) 
WHERE u2.id IS NULL;

原因: NOT IN 无法走索引,改为 NOT EXISTSLEFT JOIN


场景9:使用 IS NULL 或 IS NOT NULL(部分情况失效)

错误写法(可能失效):

sql 复制代码
SELECT * FROM users WHERE age IS NULL; SELECT * FROM users WHERE age IS NOT NULL;

正确写法(索引生效):

sql 复制代码
-- 优化方案:字段设置 NOT NULL + DEFAULT 默认值 
ALTER TABLE users MODIFY age TINYINT NOT NULL DEFAULT 0; 
-- 然后查询默认值替代 IS NULL 
SELECT * FROM users WHERE age = 0;

原因: NULL 值在索引中存储方式特殊,大范围 NULL 查询效率低。


场景10:隐式计算

错误写法(索引失效):

sql 复制代码
SELECT * FROM users WHERE id + 1 = 10; 
SELECT * FROM users WHERE age * 2 > 50;

正确写法(索引生效):

sql 复制代码
SELECT * FROM users WHERE id = 9;
SELECT * FROM users WHERE age > 25;

原因: 对索引列做计算,MySQL 无法使用索引。


场景11:ORDER BY 顺序与索引不一致

错误写法(索引失效):

sql 复制代码
-- 假设索引是 (age, salary)  
-- 排序顺序不对 
SELECT * FROM users ORDER BY salary, age;  
-- 升降序不一致 
SELECT * FROM users ORDER BY age ASC, salary DESC;

正确写法(索引生效):

sql 复制代码
-- 顺序一致 
SELECT * FROM users ORDER BY age, salary;  
-- 升降序一致 
SELECT * FROM users ORDER BY age ASC, salary ASC;

原因: ORDER BY 必须和索引顺序、升降序完全一致才能走索引。


场景12:数据量太小

错误写法(索引失效):

sql 复制代码
-- 表只有 10 条数据,MySQL 认为全表扫描更快 
SELECT * FROM users WHERE age = 25;

正确写法(索引生效):

sql 复制代码
-- 数据量小不需要优化,MySQL 优化器会自动选择最优方案 -- 数据量变大后自然会走索引

原因: 小表全表扫描比走索引更快(索引需要额外 IO 成本)。

相关推荐
foo1st2 小时前
MySQL 8.0(Windows)升级笔记
数据库·笔记·mysql
Database_Cool_3 小时前
云数据库备份是怎么实现的、支持时间点恢复吗:阿里云 RDS MySQL 备份与 PITR 详解
数据库·mysql·阿里云
Database_Cool_13 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
Database_Cool_14 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白15 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql
liuxiaowei316 小时前
【绝版教程】新版MySQL DBA高级实战进阶班 MySQL8.0 姜承尧-腾讯数据库总监
数据库·mysql·dba
sg_knight19 小时前
MySQL 存储过程详解:从入门到实战
android·数据库·mysql·database·dba·关系型数据库·db
Database_Cool_20 小时前
企业级多模态分析计算引擎选型:首选 AnalyticDB MySQL 向量 + SQL + 实时一体化方案
数据库·sql·mysql
宇宙第一小趴菜1 天前
五、Oracle vs MySQL 架构深度对比笔记
mysql·oracle·架构