
以下尖括号表示需要替换的名称或值,方括号表示可选部分;执行前应删除占位符。
索引
是帮助MySQL高效获取数据的数据结构,以空间换时间
优劣 优势: 提高检索数据的效率,降低数据库的IO成本,降低CPU的消耗 劣势: 索引需要占用空间;
INSERT、UPDATE、DELETE还需维护相关索引,可能增加写入成本。
MySQL的索引在存储引擎实现的,不同引擎有不同的结构
B+树:最常见的,大部分都支持B+树索引
Hash:支持等值查找,不支持范围查找或按索引排序。MEMORY 引擎支持显式 Hash 索引,InnoDB 也可能自动构建自适应 Hash 索引。
R-树:用于空间索引;InnoDB 和 MyISAM 都支持空间索引。
全文索引:用于文本关键字检索;InnoDB 和 MyISAM 支持 FULLTEXT 索引。
索引结构
二叉树 缺点:顺序插入时会形成一个链表,查询性能会大大降低。大数据量的情况下,层级较深,检索速度慢 Hash 通过哈希函数把键映射到槽位;发生哈希冲突时,存储引擎需要进一步比较或处理冲突。
- Hash索引仅支持对等比较(=,IN),不支持范围查询(between,>,<,。。。)
- 无法通过索引完成排序操作
- 等值查询通常很快,但实际性能取决于数据分布、冲突和执行计划,不能一概认为比 B+ 树快。
MySQL中的InnoDB对Hash有自适应,Hash索引是存储引擎根据B+树索引在指定条件下自动构建的
索引分类
| 分类 | 含义 | 特点 | 关键字 |
|---|---|---|---|
| 主键索引 | 针对表中主键创建的索引 | 默认自动创建且只能有一个 | PRIMARY |
| 唯一索引 | 避免某个字段的值出现重复 | 可以有多个 | UNIQUE |
| 常规索引 | 快速定位特点数据 | 可以有多个 | - |
| 全文索引 | 全文索引查找的是文本中的关键字,而不是比较索引中的值 | 可以有多个 | FULLTEXT |
根据存储形式划分
| 分类 | 含义 | 特点 |
|---|---|---|
| 聚集索引 | InnoDB 聚集索引叶子节点保存行数据 | 每张 InnoDB 表有一个 |
| 二级索引 | 数据与索引分开存放,叶子节点为对应行的主键 | 可以有很多个 |
聚集索引选取规则:如果存在主键,主键索引就是聚集索引
如果没有主键,InnoDB 会选择所有列都为 NOT NULL 的第一个 UNIQUE 索引。
如果也没有这样的唯一索引,InnoDB 会生成隐藏的聚集索引。
由二级索引找到主键值,再到聚集索引读取行数据,称为回表查询。
索引语法
创建索引
CREATE [UNIQUE|FULLTEXT] INDEX <INDEXNAME> ON <TABLENAME>(COLUMN,COLUMN,...);查看索引
SHOW INDEX FROM <TABLENAME>;删除索引
DROP INDEX <INDEXNAME> ON <TABLENAME>;SQL性能分析
SHOW STATUS 可查看服务器状态变量。下面的 Com_% 计数是服务器级别的语句计数,不限定当前数据库;也不等同于实际读取或修改的行数。
SHOW GLOBAL STATUS LIKE 'Com\_%';慢查询日志 慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位秒,默认10)的所有SQL语句的日志。默认不开启。需要在配置文件中配置:slow_query_log=1 和long_query_time=10。配置完成之后重启服务器
profile详情 可以帮助了解SQL语句时间消耗 可通过
have_profiling查看当前 MySQL 是否支持该功能:
SELECT @@have_profiling;SHOW PROFILE 已弃用;旧版本中可在当前会话启用,新的性能分析应优先使用 Performance Schema。
SET profiling=1;-- 查看当前会话中各语句的耗时SHOW profiles;
-- 查看指定 query_id 的各阶段耗时SHOW PROFILE FOR QUERY <QUERY_ID>;
-- 查看指定 query_id 的 CPU 耗时SHOW PROFILE CPU FOR QUERY <QUERY_ID>;explain执行计划 EXPLAIN或者DESC命令获取MySQL任何执行SELECT语句的信息,包括SELECT语句执行过程中表如何连接和连接顺序。
-- 在 SELECT 语句前加 EXPLAINEXPLAIN SELECT <COLUMN> FROM <TABLENAME>;各个字段含义
- Id
SELECT的标识符;不能只凭id大小推断实际执行顺序。
- select_type
- 表示select的类型,常见的取值由simple(简单表,即不使用表连接或子查询)、Primary(主查询,即外层的查询)、UNION(UNION中的第二以及以后的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等
- type
- 表访问类型,常见值有
system、const、eq_ref、ref、range、index、ALL;需结合行数和过滤条件判断性能。
- 表访问类型,常见值有
- possible_keys
- 显示可能应用在这张表上的索引,一个或多个
- key
- 实际使用的索引。如果为NULL,就是没有使用索引
- key_len
- 优化器选用的索引键长度,可帮助判断联合索引用了哪些列;不是越短越好。
- rows
- MySQL认为必须要执行查询的行数,在InnoDB引擎的表中是一个估计值,可能并不总是准确的
- filtered
- 估计经过表条件筛选后保留的行占
rows的百分比;需结合实际执行计划判断,不能单凭数值高低评价查询。
- 估计经过表条件筛选后保留的行占
索引的使用
最左前缀法则 联合索引通常按最左列开始使用;跳过前导列或遇到范围条件后,后续列能否用于索引查找取决于查询条件和优化器。用
EXPLAIN确认实际使用情况。 索引列运算 对索引列直接做函数或运算,通常会妨碍普通索引用于查找;可考虑改写条件或使用函数索引,并用EXPLAIN验证。 字符串不加引号 字符串值应使用引号。若比较时发生隐式类型转换,可能妨碍索引使用,具体取决于列类型和执行计划。 模糊查询LIKE 'aa%'有机会利用 B+ 树索引做范围查找;LIKE '%aa'通常不能使用普通 B+ 树索引定位前缀。 or连接的条件OR的各条件能否用索引,取决于可用索引、数据分布和优化器选择;可检查EXPLAIN中是否使用 Index Merge 或全表扫描。 数据分布影响 如果MySQL评估索引比全表慢,则不使用索引 SQL提示 在SQL语句中加入一些人为的提示优化操作
-- USE INDEXSELECT * FROM <TABLENAME> USE INDEX(<INDEXNAME>) WHERE <OPTION>;
-- IGNORE INDEXSELECT * FROM <TABLENAME> IGNORE INDEX(<INDEXNAME>) WHERE <OPTION>;
-- FORCE INDEXSELECT * FROM <TABLENAME> FORCE INDEX(<INDEXNAME>) WHERE <OPTION>;覆盖索引 当查询需要的列都可从索引取得时,可避免回表;按实际查询选择列,避免无必要的
SELECT *。
前缀索引 对较长的字符串列,可只索引前缀以减少索引占用;前缀过短会降低区分度,需要按数据分布选择长度。
CREATE INDEX <INDEX_NAME> ON <TABLE_NAME> (<COLUMN_NAME>(<PREFIX_LENGTH>));可用 COUNT(DISTINCT LEFT(列名, N)) / COUNT(*) 估计前缀的区分度。区分度越高通常越利于筛选,但实际性能仍需结合索引大小和查询计划衡量。
单列索引与联合索引 单列:一个索引只包含一列 多列:一个索引包含多列 多个条件经常一起出现时,可考虑符合列顺序的联合索引;单列索引与联合索引的取舍应依据实际查询、写入成本和
EXPLAIN结果。
索引设计原则
- 针对数据量大、且查询比较频繁的表建立索引。
- 对常作为查询条件、分组、排序的字段建立索引。
- 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
- 如果是字符串类型的索引,字符串长度较长,可以根据字段的特点建立前缀索引。
- 联合索引可覆盖部分常用查询并减少回表,但不一定比单列索引节省空间。
- 要控制索引数量,索引不是越多越好,索引越多,维护索引的代价越大,影响增删改的效率。
- 如果索引列不能存储NULL,在建表时候用NOT NULL限制,当优化器指定每列是否包含NULL时,它可以更好得确定哪个索引最有效。
视图
视图保存查询定义,通常不单独存储结果数据;查询视图时会访问其底层表。
语法
创建或修改视图
CREATE [OR REPLACE] VIEW <VIEWNAME>(NEWCOLUMNNAME1,NEWCOLUMNNAME2,...) AS <SELECT语句> [WITH [CASCADED | LOCAL] CHECK OPTION];查询视图
-- 查看创建视图语句SHOW CREATE VIEW <VIEWNAME>;
-- 查询视图数据SELECT * FROM <VIEWNAME>;删除视图
DROP VIEW <VIEWNAME>;视图的检查选项:
使用 WITH CHECK OPTION 创建可更新视图后,经该视图执行的 INSERT 和 UPDATE 必须使新行符合视图条件。
默认是 CASCADED。若视图 A 基于视图 B:CASCADED 会递归检查底层视图条件;LOCAL 检查 A 的条件,并继续按 B 自身的检查选项判断,不会强制给 B 添加检查选项。
视图的更新
要使得视图可以更新,视图与基表的行必须为一对一关系。如果视图包含以下任何一项,则视图无法更新:
- distinct
- group by
- having
- UNION or UNION ALL
- 聚合函数或窗口函数
视图的作用
- 视图可以封装常用查询,减少重复书写查询条件。
- 可以向用户授予视图权限,并通过视图定义限制其可见的数据;权限效果还取决于视图的安全上下文和底层表权限。
- 视图可以帮助用户屏蔽真实表结构变化带来的影响
存储过程
存储过程是保存在数据库中的 SQL 语句集合,可封装重复的数据库操作。
语法
创建
CREATE PROCEDURE 存储过程名称([参数列表])BEGIN SQL语句;END;调用
CALL 名称(参数);查看数据库的存储过程
SELECT * FROM INFORMATION_SCHEMA.ROUTINESWHERE ROUTINE_SCHEMA = '数据库名称' AND ROUTINE_TYPE = 'PROCEDURE';查看存储过程创建语句
SHOW CREATE PROCEDURE 存储过程名称;删除存储过程
DROP PROCEDURE [IF EXISTS] 存储过程名称;变量
在 mysql 命令行客户端中定义多语句存储程序时,需要临时更改语句结束符;DELIMITER 是客户端命令,不是 SQL。
-- 以下示例在 mysql 命令行客户端执行DELIMITER //CREATE PROCEDURE hello()BEGIN SELECT 'hello' AS message;END//DELIMITER ;系统变量
由MySQL数据库提供,不需要用户定义(全局变量GLOBAL,会话变量SESSION)
查看系统变量
SHOW [GLOBAL | SESSION] VARIABLES;
SHOW [GLOBAL | SESSION] VARIABLES LIKE '变量名模式';
SELECT @@SESSION.系统变量名;SELECT @@GLOBAL.系统变量名;设置系统变量
SET [SESSION | GLOBAL] 变量名=值;
SET @@SESSION.变量名=值;SET @@GLOBAL.变量名=值;用户变量
用户根据业务需求定义的。两个@是系统变量,一个@是用户变量,用户变量不需要提前声明类型。作用域为当前会话。
用户变量无需声明;读取尚未赋值的用户变量会得到 NULL。
赋值
SET @变量名=值,@变量名=值,...;
SELECT @变量名:=值,@变量名:=值,...;-- SELECT设置变量,必须要要用:=,SET的话:=和=都可使用
SELECT @变量名;局部变量
由DECLARE声明,只能在BEGIN和END之间使用
声明
DECLARE 变量名 类型 [DEFAULT ...];字段类型有CHAR, BIGINT, INT,VARCHAR, DATE, TIME等
赋值
SET 变量=值;SET 变量:=值;SELECT 字段 INTO 变量 FROM 表...;SELECT ... INTO 应只返回一行数据;局部变量名不带 @。
IF判断
IF 条件 THEN ...ELSEIF 条件2 THEN ...ELSE ...END IF;参数(形参)
- IN
- 需要调用时输入的,是默认的
- OUT
- 作为返回值的参数
- INOUT
- 既可以作为输入,也可以作为输出
用法
-- 使用SET对参数2进行赋值CREATE PROCEDURE 存储过程(IN 参数1 类型, OUT 参数2 类型,...)BEGIN SQL语句;END;CASE
语法一
CASE 变量 WHEN 值1 THEN SQL语句; WHEN 值2 THEN SQL语句; ... ELSE SQL语句;END CASE;语法二
CASE WHEN 条件1 THEN SQL语句; WHEN 条件2 THEN SQL语句; ... ELSE SQL语句;END CASE;WHILE
WHILE 条件 DO SQL语句;END WHILE;REPEAT
有条件的循环,满足条件则退出。
REPEAT SQL语句;UNTIL 条件END REPEAT;LOOP
可以实现简单的死循环,不在SQL中增加退出循环的条件。
LEAVE: 退出循环 ITERATE: 必须在循环中,表示跳过当前循环剩下的语句。
[开始标记]:LOOP SQL语句; -- 根据条件选择 LEAVE 或 ITERATE,通常不会连续执行二者 LEAVE 开始标记;END LOOP [结束标记];游标
用来存储查询结果集的数据类型,可以用游标进行循环处理。游标的使用包括声明、OPEN、FETCH、CLOSE。
声明
DECLARE 游标名 CURSOR FOR 查询语句;打开游标
OPEN 游标名;获取游标记录
FETCH 游标名 INTO 变量1,变量2,...;关闭游标
CLOSE 游标名;条件处理程序
定义在流程控制执行过程中遇到条件时的处理步骤。
DECLARE handler_action HANDLER FOR condition_value,... SQL;handler_action:
- EXIT 满足condition_value时退出
- CONTINUE 满足condition_value时继续
condition_value:
- SQLSTATE sqlstate_value:状态码,如SQLSTATE ‘02000’
常用的条件类别:
SQLWARNING:SQLSTATE 类别01。NOT FOUND:SQLSTATE 类别02。SQLEXCEPTION:除成功、警告和未找到之外的异常类别。
存储函数
存储函数通过 RETURN 返回值;函数参数默认都是输入参数,声明时不写 IN。
CREATE FUNCTION add_one(n INT)RETURNS INT DETERMINISTIC NO SQLRETURN n + 1;characteristic特性说明:
- DETERMINISTIC: 相同的输入参数总是产生相同的结果
- NO SQL:不包含SQL语句
- READS SQL DATA:包含查询数据的语句,但不包含写入数据的语句。
启用二进制日志且 log_bin_trust_function_creators=0 时,创建函数可能要求声明 DETERMINISTIC、NO SQL 或 READS SQL DATA;应按函数的实际行为声明,不能为绕过错误而标注不真实的特性。
触发器
触发器与表关联,在插入、更新或删除每行之前或之后执行,可用于数据校验或记录变更。 使用别名OLD和NEW来引用触发器中发生变化的记录内容。支持行级触发,不支持语句级触发。
- INSERT型触发器
- NEW表示将要或者已经新增的数据
- UPDATE型触发器
- OLD表示修改之前的数据,NEW表示将要或者已经修改后的数据
- DELETE型触发器
- OLD表示将要或者已经删除的数据
语法
CREATE TRIGGER 触发器名{BEFORE | AFTER} {INSERT | UPDATE | DELETE}ON 表名 FOR EACH ROW --行级触发器BEGIN SQL;END;查看
SHOW TRIGGERS;删除触发器
DROP TRIGGER [数据库名.]触发器名;--如果没有指定数据库则默认为当前数据库参考资料
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
MySQL 学习笔记
连载中最后更新于 ,距今已过 3 天
部分内容可能已过时
评论