Skip to content

02-MySQL 高级(函数与索引)

对应原始资料:数据库_day03mysql索引公开课笔记

一、常用函数

1. 字符串

sql
LENGTH(s) / CHAR_LENGTH(s)
CONCAT(a, b)            -- 拼接
SUBSTRING(s, start, len) -- 截取,索引从 1 开始
UPPER(s) / LOWER(s)
TRIM(s)                  -- 去两端空格
REPLACE(s, a, b)
LPAD(s, len, pad) / RPAD -- 填充
INSTR(s, sub)            -- 子串位置

2. 数值

sql
ROUND(x, d)   -- 四舍五入
CEIL(x) / FLOOR(x)
TRUNCATE(x, d)
MOD(a, b)
RAND()

3. 日期

sql
NOW() / CURDATE() / CURTIME()
YEAR(date) / MONTH / DAY / HOUR ...
DATE_FORMAT(date, '%Y-%m-%d')
STR_TO_DATE('2024-01-01', '%Y-%m-%d')
DATEDIFF(d1, d2)
DATE_ADD(date, INTERVAL 1 DAY)

4. 流程函数

sql
IF(expr, t, f)
IFNULL(expr, val)
CASE
    WHEN 条件 THEN 结果
    WHEN 条件 THEN 结果
    ELSE 结果
END

案例:

sql
SELECT name,
  CASE
    WHEN score >= 90 THEN '优秀'
    WHEN score >= 60 THEN '及格'
    ELSE '不及格'
  END 等级
FROM student;

5. 聚合 + 窗口函数(8.0+)

sql
-- 每个部门薪资排名
SELECT name, dept_id, salary,
       RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) rnk
FROM emp;
-- ROW_NUMBER()、DENSE_RANK()、LAG()、LEAD()、SUM() OVER(...)

二、视图

虚表,保存一条 SQL 的查询结果,简化复杂查询。

sql
CREATE VIEW v_emp_dept AS
SELECT e.id, e.name, d.name dname FROM emp e JOIN dept d ON e.dept_id = d.id;

SELECT * FROM v_emp_dept;
DROP VIEW v_emp_dept;

视图不存真实数据,查询时仍走原始表。可用于权限隔离、简化复杂查询。不推荐用视图做写操作

三、存储过程与函数(了解)

预编译存于数据库的 SQL 集合。互联网项目用得少(业务逻辑放代码层)。

sql
DELIMITER $
CREATE PROCEDURE pro_test(IN n INT, OUT result INT)
BEGIN
    SELECT COUNT(*) INTO result FROM emp WHERE dept_id = n;
END $
CALL pro_test(1, @r);
SELECT @r;

四、索引(重点中的重点)

1. 为什么需要索引

  • 没有索引:全表扫描,数据量大时慢。
  • 有索引:像书的目录,快速定位,查询效率从 O(n) → O(log n)。

2. 索引结构(InnoDB)

  • 默认 B+ 树索引:
    • 只有叶子节点存数据,非叶子节点只存索引。
    • 叶子节点形成有序双向链表,范围查询极快
  • 聚簇索引:数据和主键索引在一起(主键就是聚簇索引)。
  • 二级索引:叶子节点存主键值,需要"回表"。

3. 索引分类

类型说明
主键索引PRIMARY KEY,唯一且非空
唯一索引UNIQUE
普通索引INDEX / KEY
联合索引多列组合
全文索引FULLTEXT,文本搜索

4. 创建索引

sql
CREATE INDEX idx_name ON emp(name);
ALTER TABLE emp ADD INDEX idx_age (age);
ALTER TABLE emp ADD UNIQUE INDEX uk_phone (phone);
CREATE INDEX idx_dept_salary ON emp(dept_id, salary);   -- 联合索引

5. 最左前缀法则

联合索引 (a, b, c) 可以用于:a / a,b / a,b,c不能跳过 a。 范围查询右侧的列失效(如 a > 1 and b = 2,b 用不上索引)。

6. 索引失效的常见场景

  • 对索引列做运算或函数:WHERE salary * 2 > 10000
  • 隐式类型转换:WHERE phone = 13800000000(phone 是 varchar)。
  • LIKE '%xxx'(左侧 % 不走索引)。
  • OR 两侧不全有索引。
  • 不符合最左前缀。
  • 数据分布(优化器认为全表更快)。

7. explain 执行计划

sql
EXPLAIN SELECT * FROM emp WHERE name = '张三';

关注列:

  • typesystem > const > eq_ref > ref > range > index > ALL,至少要达到 range/ref,避免 ALL
  • key:实际使用的索引。
  • rows:预估扫描行数。
  • ExtraUsing index(覆盖索引,好)、Using filesort(额外排序,差)、Using temporary(用临时表,差)。

8. 索引使用建议

  • 主键、外键、唯一约束自动建索引。
  • 查询频繁、区分度高、数据量大的列建索引。
  • 增删改频繁、数据少的表、WHERE 用不到的列,不建。
  • 联合索引把区分度高、常用的列放前面。
  • 单表索引数建议不超过 5 个。

五、数据库备份与还原

bash
mysqldump -u root -p db1 > db1.sql            # 备份单个库
mysqldump -u root -p db1 t1 t2 > tables.sql   # 备份表

mysql -u root -p db1 < db1.sql                # 还原

或在 DataGrip / Navicat 中图形化导出导入。

练习建议

  1. 用聚合函数统计各部门人数、平均薪资、最高薪资。
  2. 用 CASE 把成绩转成"优秀/及格/不及格"。
  3. emp 表的 namedept_id, salary 建索引,用 explain 观察前后的 typerows
  4. 设计一个 SQL 让索引失效(如 LIKE '%xx'、列运算),对比执行计划。
  5. 用 mysqldump 备份一个库,删表后再还原。