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

MySQL数据库——事务、索引和视图

目录

前言

一、事务:数据世界的“保险柜”

1、概述

2、ACID四大特性

3、隔离级别:解决并发冲突

①出现的问题

②解决的方式

二、索引:数据库的“目录”

1、概述

①索引优缺点:

②创建原则:

2、存储引擎

3、索引分类

单列索引

①普通索引

②主键索引

③唯一索引

组合索引(复合索引)

全文索引

三、视图:数据库的“定制窗口”

1、概述

2、优点

3、分类

①简单视图

②复杂视图

4、视图的管理与维护

①查看视图:知道数据库里有哪些视图

②重命名视图:改个更易懂的名字

③修改视图:更新视图的查询逻辑

④删除视图:不用的视图及时清理

5、视图的常用场景

①数据权限控制

②简化复杂查询

③分解复杂查询逻辑

四、数据库优化

1、事务使用建议

2、索引优化

3、查询优化

4、设计优化


前言

在数据库的江湖里

有“三剑客”默默守护着数据安全查询效率

今天就让我们来看看他们三位怎么个事

一、事务:数据世界的“保险柜”

1、概述

事务就像人一样有“完美主义强迫症”

它不允许出现半吊子情况出现

要么全成功,要么全失败

所以它就是用来应对“操作一般出问题”的情况

事务(Transaction):

由一系列操作组成的一个执行逻辑单元

操作包括:对数据库表中数据进行访问与更新

一些简单注意事项:

  • 只有DML语句才会产生事务,其他语句不会产生事务
  • DML语句执行的时候,如果当前有事务,那么就使用这个事务。如果当前没有事务,则产生一个新事务
  • commit、rollback、DDL语句都可以把当前事务给结束掉

        commit和DDL语句:把这个事务给提交了,然后DML操作永久生效

        rollback:把这个事务给回滚了,默认回滚到事务开始的状态

  • mysql默认是开启事务,即 autocommit = 1,自动提交事务。即执行 insert、update、delete操作,立刻提交。

        也就是说,每个SQL语句都被看做一个独立的事务

        如果复杂业务需要显示控制事务

        可以使用 BEGIN、COMMIT和ROLLBACK语句手动管理事务的生命周期

事务生命周期:

  1. 开始(BEGIN):事务的生命周期始于BEGIN语句的执行。在开始阶段, MySQL会为该事务分配一个唯一的事务ID,并开始记录事务日志
  2. 执行(执行SQL语句):在事务开始后,可以执行多个SQL语句,包括插入(INSERT)、更新(UPDATE)、删除(DELETE)等操作。这些操作会在事务日志中进行记录,但并不会立即影响数据库的实际数据
  3. 提交(COMMIT):当所有SQL语句执行完毕后,可以选择提交事务。提交操作会将事务中的所有修改永久保存到数据库中,并释放相关的锁资源
  4. 回滚(ROLLBACK):在事务执行过程中,如果发生错误或需要取消之前的修改,可以选择回滚事务。回滚操作会撤销事务中的所有修改,恢复到事务开始前的状态
  5. 结束(END):事务的生命周期在提交或回滚后结束。结束阶段会释放所有与该事务相关的资源,并关闭事务日志

示例:模拟转账

-- 开启事务
BEGIN;  -- 方式1
START TRANSACTION;  -- 方式2
SET AUTOCOMMIT=0;  -- 方式3:关闭自动提交,后续操作需手动提交-- 执行转账操作
-- 张三扣100(假设张三id=1,李四id=2)
UPDATE t_account SET balance=balance-100 WHERE id=1;
-- 李四加100
UPDATE t_account SET balance=balance+100 WHERE id=2;-- 提交或回滚
-- 没问题就提交,锁死数据
COMMIT;  -- 转账成功,数据永久生效
-- 出错就回滚
ROLLBACK;  -- 比如李四id输错了,回滚后张三余额不变-- 进阶:设置回滚点
-- 如果事务中有很多操作,想回滚到某个步骤,用SAVEPOINT
BEGIN;
INSERT INTO t_user VALUES(1,'tom',1000);  -- 操作1
SAVEPOINT A;  -- 设回滚点A
INSERT INTO t_user VALUES(2,'zs',2000);  -- 操作2
SAVEPOINT B;  -- 设回滚点B
DELETE FROM t_user;  -- 操作3(不小心删多了)
ROLLBACK TO A;  -- 回滚到A,操作2和3失效,只剩操作1
COMMIT;  -- 最终只保存了tom的数据

注意事项:

        rollback to 回滚点

        此时事务并没有结束,可以继续回滚(rollback)提交(commit)

2、ACID四大特性

事务有四个黄金法则, 根据英文首字母简称 ACID:

  • 原子性(Atomicity):操作要么全成功,要么全失败,就像原子一样不可分割
  • 一致性(Consistency):事务执行前后,数据库必须保持一致性状态
  • 隔离性(Isolation):多个事务并发执行时,彼此之间互不干扰
  • 持久性(Durability):一旦事务提交,对数据的改变就是永久的

简单解释一下:

A:比如转账,张三给李四转 100 元,要么张三扣 100、李四加 100,要么都不变(比如断电了),绝不会出现 “张三扣了钱,李四没收到” 的情况

C:转账前两人总余额是 2000,转账后还是 2000,不会多也不会少

I:张三转账时,李四查自己余额,要么看到转账前的数,要么看到转账后的数,绝不会看到 “正在转的中间数”

D:一旦转账成功,就算数据库崩溃,重启后数据还是对的,钱不会凭空消失

3、隔离级别:解决并发冲突

多人同时查改数据,就可能导致以下三大问题(并发冲突):

①出现的问题

  • 脏读

会话1 读到了 会话2 的数据

比如说抄作业

  • 小明在写数学作业,写的答案是50(还没提交)
  • 你瞟了一看正好看到了
  • 结果小明发现写错了,擦掉改成45了
  • 但是你知道的还是错误的50

        

读到了别人还没 COMMIT 的数据

  • 不可重复读

在同一事务中,两次读取同一数据,得到内容不同

比如看商品价格:

  • 你看中一件衣服标价100元
  • 你问售货员多少钱,他说“100元”
  • 你觉得有点贵先去别的家看看
  • 这时老板过来把价格改为80元
  • 你转了一圈回来又问售货员,他说“80元”
  • 同一件衣服,你两次问价得到了不同的结果

        

同一个数据,短时间内查询结果不一样

  • 幻读

同一事务中,用同样的操作读取两次,得到的记录数不相同

比如大学查课

  • 你是学生会查课的同学
  • 拿出花名册开始点名
  • 点完之后数了一遍来了82个人
  • 正准备去汇报时迎面撞上一位拿着咖啡的老师
  • 花名册被洒了的咖啡弄的不成样子只能再点一遍
  • 但是你没有发现教室后面偷偷溜进来的三位同学
  • 重新点完数了一遍变成85个人
  • 你很疑惑:诶?我出现幻觉了吗

        

同样的查询条件,返回的记录数量变了

②解决的方式

MySQL定义了四种隔离级别用来应对上述三种情况:

隔离级别脏读(读未提交)不可重复读(同一事务查两次结果不同)幻读(同一事务查两次记录数不同)
读未提交(最低)✅ 允许✅ 允许✅ 允许
读已提交❌ 禁止✅ 允许✅ 允许
可重复读(默认)❌ 禁止❌ 禁止✅ 允许
串行化(最高)❌ 禁止❌ 禁止❌ 禁止

不难发现

级别越高安全性越高,但是实时性能也越慢

示例:查看 / 修改隔离级别

-- 查看当前隔离级别
SHOW VARIABLES LIKE '%isolation%';-- 修改为“读已提交”(当前会话生效)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

注意:

        上述修改只在当前会话中生效

        想要永久修改需要修改mysql配置文件

-- 恢复成默认隔离级别
set session transaction isolation level REPEATABLE READ;

二、索引:数据库的“目录”

1、概述

没有目录时,你得一页一页翻

有了目录可以快速锁定页码找到你要的内容

索引(Index):

是一种数据结构,用于提高数据库表的查询性能

索引可以加速数据的检索,减少查询所需的时间和资源消耗。

①索引优缺点:

  • 优点:加快数据检索速度,提高查找效率
  • 缺点:占用数据库物理存储空间,当对表中数据更新时,索引需要动态维护,降低数据写入效率

②创建原则:

  • 对where 和 order by 涉及的列上尽量建立索引
-- 没有索引的情况(全表扫描)
SELECT * FROM books 
WHERE title LIKE '%MySQL优化%' 
ORDER BY publish_year;
-- 需要一页页翻阅所有书籍,找到符合条件的再排序-- 有索引的情况
CREATE INDEX idx_title_year ON books(title, publish_year);
-- 直接查目录,快速定位到相关书籍并按顺序排列

  • 更新频繁的列不应设置索引
-- 用户状态频繁变化的表
UPDATE users SET last_login = NOW() WHERE user_id = 1;  -- 每次登录都更新
UPDATE users SET online_status = 1 WHERE user_id = 1;   -- 频繁上下线-- 如果给这些字段建索引
CREATE INDEX idx_last_login ON users(last_login);
CREATE INDEX idx_online_status ON users(online_status);

    每次UPDATE / INSERT/DELETE时,数据库需要:

  1. 修改数据本身 ✅(必须的)
  2. 更新相关索引 ❌(额外开销)

  • 数据量小的表不要使用索引

        索引占用额外存储空间,维护成本更高

  • 重复数据多的字段不应设为索引(如性别,只有男和女),重复数据超 15%就不该建索引

也可以简单算一下看看适不适合:

选择性 = 不同值的数量 / 总记录数选择性 > 0.85:非常适合建索引
选择性 0.5-0.85:可以考虑建索引
选择性 < 0.15:不适合建索引

示例:

-- 检查字段选择性
SELECT COUNT(DISTINCT gender) as distinct_values,COUNT(*) as total_records,COUNT(DISTINCT gender) / COUNT(*) as selectivity
FROM users;-- 结果示例:
-- distinct_values: 2
-- total_records: 10000  
-- selectivity: 0.0002  -- 太低了,不适合建索引

2、存储引擎

在 MySQL 中,存储引擎(Storage Engine)是负责处理数据的存储和检索的模块

MySQL 支持多种存储引擎

不同的存储引擎可以在不同的应用场景中提供不同的优势和特性

常见的有:

  • InnoDB:MySQL 5.5 版本之后的默认存储引擎,适用于需要事务支持高并发读写操作的应用场景
  • MyISAM:MySQL 5.5 版本之前的默认存储引擎,它以其简单和高性能而闻名,适用于大量的读操作和只读数据
  • Memory:或称为 Heap存储引擎,将数据存储在内存中,提供了非常快速的读写性能但是,由于数据存储在内存中,重启服务器或断电会导致数据丢失,Memory 引擎适用于临时数据存储和高速缓存等场景

InnoDB用的底层数据结构是 B+树

为什么不用哈希、二叉树哪些呢?

  • 哈希索引:像查字典的 “部首目录”,精确匹配快,但范围查询(比如 “薪水 > 5000”)直接歇菜,因为哈希值是无序的,无法进行大小比较
  • 二叉树数据多了会变成 “歪脖子树”(像链表),查最后一个数据要遍历所有节点,慢得很
  • B + 树:多叉树,每个节点中可以存储多个数据,且每个节点中数据是有序的,树的高度值更小,查询效果更高。查范围(比如 “id 10-20”)直接扫叶子节点的双向链表,又快又稳,还能减少磁盘 IO

不过 B+树 也有弊端:

  • 范围查找效率不高,比如查询 [20,39]
  • 查询效率不稳定:离根节点近则查询快,远则慢
  • 树高度还有下降空间(数据库优化方向,让树更矮胖,提高查询性能,但是会牺牲内存空间)

3、索引分类

按功能划分:

常用:单列索引(普通索引、主键索引、唯一索引)组合索引、全文索引

了解:空间索引、其他索引

  • 单列索引

①普通索引

语法:

CREATE TABLE [IF NOT EXISTS] tb_name [(
字段1 数据类型 [约束条件] [默认值] [COMMENT '注解'], 
字段2 数据类型 [约束条件] [默认值] [COMMENT '注解'], 
字段3 数据类型 [约束条件] [默认值] [COMMENT '注解'],
[表约束条件]
index index_name(col_name...)
)][engine=innodb] [default charset=utf8];或
create index index_name on tb_name(col_name);或
alter table tb_name add index index_name(col_name);

示例1:创建教师表,指定普通索引

create table tea(
id int primary key auto_increment,
name varchar(20),
age int,
index index_name(name)
);

示例2:创建教师表之后构建索引

create table tea1(
id int primary key auto_increment,
name varchar(20),
age int
);
create index index_name on tea1(name);

示例2:创建教师表之后构建索引

create table tea2(
id int primary key auto_increment,
name varchar(20),
age int
);
alter table tea2 add index index_name(name);

查看xxx数据库中的全部索引

select *
from mysql.innodb_index_stats
where database_name='xxx';

②主键索引

创建表时,MySQL会自动在主键列上建立一个索引

具有唯一性,不允许为NULL

示例:创建教师表,设置id为主键索引

create table tea4(
id int primary key auto_increment,
name varchar(20),
age int
);或
create table tea4(
id int,
name varchar(20),
age int
);
alter table tea4 add primary key(id);

③唯一索引

和普通索引类似,不同点:

索引列的值必须唯一,但允许为NULL,如果是组合索引,列值的组合必须唯一

示例:

create table tea3(
id int primary key auto_increment,
name varchar(20),
age int,
unique index_name(name)
);或
create table tea3(
id int primary key auto_increment,
name varchar(20),
age int
create unique index index_name on tea3(name);或
create table tea3(
id int primary key auto_increment,
name varchar(20),
age int
);
alter table tea3 add unique index_name(name);

  • 组合索引(复合索引

多个列一起建索引,遵循 “最左原则”

示例:创建教师表,设置id和名字为组合索引

create table tea5(
id int,
name varchar(20),
age int,
index index_name(id,name)
);或
create table tea5(
id int,
name varchar(20),
age int
);
create index index_name on tea5(id,name);或
create table tea5(
id int,
name varchar(20),
age int
);
alter table tea5 add index index_name(id,name);

注意:

以现在的索引是(id,name)这个顺序为例

  1. where id=1 可以使用索引,条件里面必须包含索引前面的字段才能够进行匹配
  2. where name='张三' 不可以使用索引(如果索引是(name,id)就可以)
  3. where name='张三' and id=12 可以使用索引,mysql本身就有一层sql优化,他会根据sql来识别出来该用哪个索引
  4. where id=12 and name='张三' 可以使用,顺序一致

  • 全文索引

文本搜索专用,关键字 fulltext

要求:

  • MySQL 5.6 以前的版本,只有 MyISAM 存储引擎支持全文索
  • MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存储引擎均支持全文索引
  • 只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引
  • 数据量较大时,先将数据放入一个没有全局索引的表中,然后再用create index创建fulltext索引,要比先建立一张表(包含fulltext索引),然后再将数据写入的速度快很多

为什么要全文索引?

  • like + % 在文本比较少时是合适的,但是对于大量的文本数据检索,是不可想象的。
  • 全文索引在大量的数据面前,能比 like + % 快 N 倍,速度不是一个数量级,但是全文索引可能存在精度问题

示例(创建):创建表Poetry,收录诗歌

create table Poetry(
id int primary key auto_increment,
name varchar(20),
content text,
fulltext(content)
);-- 或
create table Poetry(
id int primary key auto_increment,
name varchar(20),
content text
);
create fulltext index index_content on Poetry(content);-- 或
create table Poetry(
id int primary key auto_increment,
name varchar(20),
content text
);
alter table Poetry add fulltext index_content(content);

示例(搜索):基于全文检索查询含有And内容

MATCH(字段列表) AGAINST(搜索内容 [搜索模式])
select *
from Poetry
where match(content) against('And');

注意:

AGAINST必须与MATCH()函数配合使用

三、视图:数据库的“定制窗口”

1、概述

视图是 “虚拟表”,不是真的存数据,而是保存一条查询语句

它是基于一个或多个表的查询结果构建而成的

视图提供了一种方便和灵活的方式来处理复杂查询、控制数据访问和重用查询逻辑

语法:

CREATE [OR REPLACE] VIEW view_name [(字段列表)]
AS
select语句
[WITH [CASCADED |LOCAL] CHECK OPTION]
  • select语句

        表示一个完整的查询语句,将查询记录映射到视图中

  • [with [cascaded | local] check option]

        可选项,表示更新视图时要保证在该视图的权限范围之内

2、优点

  • 简化查询:复杂的多表联查,保存成视图后,下次直接SELECT * FROM 视图名,不用再写长 SQL。
  • 数据安全:不同角色看不同视图,销售看不到成本,实习生看不到核心客户。
  • 减少冗余:多个地方用同一查询逻辑,只需要维护一个视图
-- 创建视图:只包含员工编号和姓名
CREATE VIEW v_emp_basic AS
SELECT id, name FROM emp;-- 销售人员查询时,只能看到视图中的数据,看不到薪水
SELECT * FROM v_emp_basic;

3、分类

①简单视图

只关联一张表,查询逻辑简单(无聚合、无多表 join、无函数计算)

数据能 “双向同步”—— 修改视图会同步到原表,修改原表也会同步到视图

案例:单表视图的创建与更新

第一步:先建基础表empdept

-- 部门表
CREATE TABLE dept(id INT PRIMARY KEY,name VARCHAR(20)  -- 部门名:java、bigdata、web
);
INSERT INTO dept VALUES(1,'java'),(2,'bigdata'),(3,'web');-- 员工表(含外键关联部门)
CREATE TABLE emp(id INT PRIMARY KEY,name VARCHAR(20),salary DOUBLE,  -- 敏感字段:薪水dept_id INT,FOREIGN KEY(dept_id) REFERENCES dept(id)
);
INSERT INTO emp VALUES(1,'lisi',3000,1),(2,'wangwu',3200,1),(3,'zhansan',2800,1);

第二步:创建简单视图(只查emp表的idname

创建简单视图(只查emp表的id和name)

第三步:操作视图,观察与原表的同步

-- 1. 查视图:只能看到id和username,看不到salary
SELECT * FROM v_emp_simple;
-- 结果:
-- id | username
-- 1  | lisi
-- 2  | wangwu
-- 3  | zhansan-- 2. 插入视图:会同步到emp表
INSERT INTO v_emp_simple VALUES(4,'zhaoliu');
-- 查原表emp:新增了id=4、name=zhaoliu,salary和dept_id为NULL
SELECT * FROM emp;-- 3. 更新视图:同步到emp表
UPDATE v_emp_simple SET username='zhaosi' WHERE id=4;
-- 查原表emp:id=4的name变成zhaosi-- 4. 删除视图数据:同步删除emp表数据
DELETE FROM v_emp_simple WHERE id=4;
-- 查原表emp:id=4的记录被删除

②复杂视图

基于多表 join、聚合函数(SUM/COUNT)、子查询等复杂逻辑构建的视图

不支持更新因为数据来自多个表,无法确定该修改哪个原表),只能用于查询

案例:多表关联的复杂视图

需求:创建视图,显示员工姓名、所属部门名、薪水(关联empdept表)

第一步:创建复杂视图

CREATE VIEW v_emp_dept AS
SELECT CONCAT(e.name, '(', d.name, ')') AS username,  -- 拼接员工名+部门名(如lisi(java))e.salary,e.dept_id,d.name AS dept_name
FROM emp e
JOIN dept d ON e.dept_id = d.id;  -- 多表join

第二步:查询视图(正常使用)

SELECT * FROM v_emp_dept;

第三步:尝试更新视图(报错

-- 试图修改拼接后的username,报错
UPDATE v_emp_dept SET username='jack(java)' WHERE dept_id=1;
-- 错误信息:ERROR 1348 (HY000): Column 'username' is not updatable

为什么不能更新?

因为usernamee.named.name拼接的结果

数据库不知道该修改emp表的name,还是dept表的name

而且视图来自多表 join,更新逻辑不明确,所以 MySQL 直接禁止

        

文档明确的 “不可更新视图” 场景

只要视图包含以下任意一种结构,就不能更新:

 
  • 聚合函数(SUM/COUNT/AVG/MAX/MIN);
  • DISTINCT(去重);
  • UNION/UNION ALL(合并结果集);
  • 多表JOIN
  • GROUP BY/HAVING(分组统计);
  • 选择列表中的子查询;
  • 数学表达式(如salary*12);
  • 常量视图(如CREATE VIEW v_const AS SELECT 'briup' AS company;

4、视图的管理与维护

①查看视图:知道数据库里有哪些视图

-- 方法1:查看当前数据库所有表和视图(视图会和表一起显示)
SHOW TABLES;
-- 结果中,视图名(如v_emp_simple)和表名(如emp)并列,可通过后续命令区分-- 方法2:查看视图的定义(最实用,知道视图是怎么建的)
SHOW CREATE VIEW v_emp_dept;
-- 会显示创建视图的完整SQL语句,方便排查问题-- 方法3:从系统表查询,明确区分视图和表
SELECT TABLE_NAME, TABLE_TYPE 
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_SCHEMA = '你的数据库名'  -- 替换成你的库名,比如briupAND TABLE_TYPE = 'VIEW';  -- 只查视图

②重命名视图:改个更易懂的名字

-- 语法:RENAME TABLE 旧视图名 TO 新视图名
RENAME TABLE v_emp_simple TO v_emp_basic_info;
-- 重命名后,用新名字调用
SELECT * FROM v_emp_basic_info;

③修改视图:更新视图的查询逻辑

如果业务需求变了(比如视图要加个dept_id列)不用删了重建直接修改:

-- 语法:ALTER VIEW 视图名 AS 新的SELECT语句
ALTER VIEW v_emp_basic_info AS
SELECT id, name, dept_id FROM emp;  -- 新增dept_id列-- 查修改后的视图:多了dept_id列
SELECT * FROM v_emp_basic_info;

④删除视图:不用的视图及时清理

-- 语法:DROP VIEW [IF EXISTS] 视图名
DROP VIEW IF EXISTS v_emp_dept;  -- IF EXISTS:避免视图不存在时报错

5、视图的常用场景

①数据权限控制

  • 销售人员:只能看员工的idnamedept_id看不到salary
  • 部门经理:能看本部门员工的idnamesalary
  • 高管:能看所有员工的完整数据

解决方案:给不同角色建不同视图不用修改代码只需控制视图权限:

-- 给销售人员的视图(无salary)
CREATE VIEW v_sales_emp AS SELECT id, name, dept_id FROM emp;-- 给部门经理的视图(只看本部门,假设经理是java部门,dept_id=1)
CREATE VIEW v_manager_emp AS 
SELECT id, name, salary FROM emp WHERE dept_id=1;-- 给高管的视图(完整数据)
CREATE VIEW v_admin_emp AS SELECT * FROM emp;

②简化复杂查询

如果经常需要查 “员工 + 部门 + 薪水等级”(关联empdeptsalgrade三张表)

每次写长 SQL 很麻烦用视图封装:

-- 创建复杂视图:关联三张表
CREATE VIEW v_emp_full_info AS
SELECT e.id,e.name,d.name AS dept_name,s.name AS sal_grade  -- 薪水等级(来自salgrade表)
FROM emp e
JOIN dept d ON e.dept_id = d.id
JOIN salgrade s ON e.salary BETWEEN s.minsal AND s.maxsal;-- 下次查询只需一行
SELECT * FROM v_emp_full_info;

③分解复杂查询逻辑

如果有一个超复杂的查询(比如多表 join + 子查询 + 聚合)

可以拆成多个简单视图

逐步组合降低难度。
比如 “查各部门平均薪水及等级”可以拆两步:

 
  1. 先建 “部门平均薪水” 视图;
  2. 再关联 “薪水等级表” 建最终视图
-- 步骤1:部门平均薪水视图
CREATE VIEW v_dept_avg_sal AS
SELECT dept_id, AVG(salary) AS avg_sal 
FROM emp GROUP BY dept_id;-- 步骤2:关联薪水等级,得到最终视图
CREATE VIEW v_dept_sal_grade AS
SELECT d.name AS dept_name,v.avg_sal,s.name AS sal_grade
FROM v_dept_avg_sal v
JOIN dept d ON v.dept_id = d.id
JOIN salgrade s ON v.avg_sal BETWEEN s.minsal AND s.maxsal;

四、数据库优化

1、事务使用建议

  • 事务不宜过长,尽快提交以释放锁资源
  • 合理设置隔离级别,平衡一致性和性能
  • 对于只读操作,考虑使用较低的隔离级别

2、索引优化

  • WHERE/ORDER BY涉及的列建索引
  • 用组合索引代替多个单列索引(比如(dept_id, salary)比单独建两个索引好)

3、查询优化

  • 尽量不使用 NULL

  通常索引字段不存在NULL

  IS NULL或者IS NOT NULL 会导致索引无法使用,进而导致查询性能低下

  • 别用SELECT *,只查需要的列
  • 避免LIKE '%关键词%'(用全文索引代替)
  • EXISTS代替IN(子查询更快)
  • 减少子查询

  执行子查询时,会创建临时表,查询完毕后再删除它,所以子查询的速度会受到影响

  • 避免排序

有些时候,数据库会暗中排序,比如这些:

  • group by 子句
  • order by 子句
  • 聚合函数(sum、count、avg、max、min)
  • distinct
  • 集合运算符(union、intersect、except)
  • 窗口函数(rank、row_number等)

所以:

  • 能写在 WHERE 子句里的条件不要写在 HAVING 子句里。
  • 如果需要对两张表的连接结果进行去重,可以考虑使用exists代替distinct,以避免排序

4、设计优化

  • 字段默认值别设为 NULL(NULL 不进索引)
  • 表字段尽量小(比如用INT不用BIGINTCHAR(6)存邮编够了)
  • 大表分表(数据超 100 万行,考虑水平拆分或垂直拆分)

事务、索引、视图并不是孤立存在的

它们经常协同工作

事不宜迟,赶快尝试一下吧!

http://www.xdnf.cn/news/20367.html

相关文章:

  • Linux基础指令(入门必备2.0)
  • B.50.10.06-NoSQL数据库与电商应用
  • 深度学习:CNN 模型训练中的学习率调整(基于 PyTorch)
  • nVisual从入门到精通—应用实例
  • 【51单片机8*8点阵显示箭头动画详细注释】2022-12-1
  • vim 常用快捷键汇总
  • 学习 Android (二十) 学习 OpenCV (五)
  • FastVLM-0.5B 模型解析
  • React Hooks UseCallback
  • Docker Registry 实现原理、适用场景、常用操作及搭建详解
  • CRYPT32!CryptMsgUpdate函数分析两次CRYPT32!PkiAsn1Decode的作用
  • Linux之Docker虚拟化技术(四)
  • 解决Vue Canvas组件在高DPR屏幕上的绘制偏移和区域缩放问题
  • Process Explorer 学习笔记(第三章3.2.1):主窗口与进程列表详解
  • 9.5C++作业
  • Ruoyi-vue-plus-5.x第五篇Spring框架核心技术:5.2 Spring Security集成
  • 使用PyTorch构建卷积神经网络(CNN)实现CIFAR-10图像分类
  • 1688 商品详情抓取 API 接口接入秘籍:轻松实现数据获取
  • LeetCode Hot 100 第11天
  • 微前端架构:解构前端巨石应用的艺术
  • 【Android】制造一个ANR并进行简单分析
  • Kotlin中抽象类和开放类
  • 《从报错到运行:STM32G4 工程在 Keil 中的头文件配置与调试实战》
  • CRYPT32!ASN1Dec_SignedDataWithBlobs函数分析之CRYPT32!ASN1Dec_AttributesNC的作用是得到三个证书
  • 垃圾回收算法详解
  • 《sklearn机器学习——回归指标2》
  • Java内部类
  • 再读强化学习(动态规划)
  • 时隔4年麒麟重新登场!华为这8.8英寸新「手机」给我看麻了
  • 《Ceph集群数据同步异常的根因突破与恢复实践》