mysql
索引
什么是索引
- 索引是一种数据结构,由数据表中的一列或多列组合而成,可以快速查询、更新数据表中的数据。如果存储引擎是MyIsam或者是InnoDB,那么底层数据结构是B+树,如果是Memory存储引擎,底层结构是Hash表
- 简而言之,索引就相当于书的目录,为了方便查找内容,通过对内容建立索引形成目录,索引可以大大提高mysql的检索效率
缺点:创建索引和维护索引要耗费时间,索引文件也会占用物理空间
索引类型
不同类型的索引,可以为不同场景提供更好的性能。在MySQL中,索引是在存储引擎层面实现的
- 普通索引:基本的索引类型,值可以为空
- 主键索引:是一种唯一索引,只能有一个主键,不允许为空
- 唯一索引:索引列的所有值都只能出现一次,即必须唯一,值可以为空
- 组合索引:多列值(多个字段)组成一个索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用
- 全文索引:Full-text索引,用于查找文本中的关键词,而不是直接比较是否相等。
Hash索引
基于hash表实现,只有查询条件精确匹配Hash索引中的列时,才会用到。对于表中每一行的数据,对于Hash索引中的所有列,存储引擎会为每一行的数据计算出一个hashcode,hash索引中存储的就是hashcode
可以快速定位,适合等值查询
B+树
二叉树
:每个节点最多有两个“叉”,也就是两个子节点,分别是左子节点和右子节点。第i层最多有 2^(i-1) 个结点。
2号:是一颗满二叉树(叶子节点全部在最底层,除了叶子节点外,每个节点都有左右两个子节点)
3号:是一颗完全二叉树(叶子节点都要在最下面两层,最后一层的叶子节点都要往左,除了最后一层,其它层的节点个数都要满)
存储二叉树的两种方法:
- 链式存储法:基于指针或引用 绝大多数二叉树实现(每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。)
- 顺序存储法:基于数组(存储完全二叉树,如果是其它的有很多空节点子树,会浪费空间)
堆其实就是一种完全二叉树,最常用的存储方式就是数组。
二叉树的遍历
- 前序遍历:对于树的任意节点来说,先打印这个节点,再打印完它的左子树,最后打印它的右子树
- 中序遍历:对于树的任意节点来说,先打印它的左子树,再打印本身,最后打印它的右子树
- 后序遍历:对于树的任意节点来说,先打印它的左子树,再打印右子树,最后打印本身
二叉查找(搜索)树
二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。
键对应user表中的id,数据对应user表中的行数据。
二叉平衡树
比如上面的数据从小到大排序,导致二叉查找树可能会形成一个链表,树的高度太高,查找的效率就会变低。为了解决这个问题,就诞生了二叉平衡树,也叫AVL树,在满足二叉查找树特性的基础上,要求每个节点的左右子树的高度不能超过1,比二叉查找树更加稳定,效率也更高

B树
当我们把数据持久化存储时(存储在磁盘),从磁盘读取数据是按块来读的,每次读取一个树节点数据,也就是读取磁盘块,平衡二叉树每个节点存储一个键值对数据,那就说明每个磁盘只存一个键值对数据,如果数据过多,我们知道从磁盘读取数据是非常慢的,我们查找数据时会进行多次IO,效率会非常慢。
为了解决平衡二叉树的这个弊端,我们应该寻找一种单个节点可以存储多个键值和数据的平衡树。也就是我们接下来要说的B树。

B+树
是B树的进一步优化
- B+树非叶子节点上是不存储数据的,仅存储键值。如果不存储数据,就会储存更多的键值,假如一个节点存储了100个键值(每个叶子节点也存储100个数据),那么三层的B+树可以存储:
100*100*100
=1000000(一百万条数据),而且只需两次IO - B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。
- 数据页之间通过双向链表连接以及叶子节点中数据之间通过单向链表连接的方式可以找到表中所有的数据。
- MyISAM中的B+树索引实现与innodb中的略有不同。在MyISAM中,B+树索引的叶子节点并不存储数据,而是存储数据的文件地址。
聚簇索引和非聚簇索引
在InnoDB里,存储B+树叶子节点整行数据的是主键索引,也被称为聚簇索引,即将数据和索引放在了一块,找到索引就找到了数据。
以主键以外的列值作为键值构建的B+树索引,我们称为非聚簇索引,非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。
数据即索引,索引即数据
在MyISAM中,聚集索引和非聚集索引的叶子节点都会存储数据的文件地址。
非聚簇索引一定会回表吗
不一定,如果查询语句所要求的字段全部命中了索引,就不会进行回表;一个索引包含(覆盖)了所有需要查询覆盖的值,也称为“覆盖索引”。
联合索引是什么?
联合索引就是将多个字段作为索引,想要命中索引,需要按照创建索引字段顺序来使用,否则无法命中
mysql最左前缀原则
最左前缀就是最左优先,在创建多列索引时,根据业务需求,将where子句中使用最频繁的一列放在最左边
前缀索引
当我们的索引字段长度过长时,又占空间,又难维护;这个时候如果可以只用索引列开始的部分字符串,那么就可以节约索引空间,从而提高索引效率(索引值重复性越低,查询效率就越高)
查看mysql语句当前使用的索引
使用:explain sql语句
创建索引三种方式
- 在创建表的时候指定
CREATE TABLE user(
#建立主键索引并设置自增
id INT auto_increment PRIMARY KEY,
first_name VARCHAR(16),
last_name VARCHAR(16),
id_card VARCHAR(18),
information text,
#建立联合索引
KEY sname (first_name,last_name),
#建立外键
UNIQUE KEY id_card (id_card),
#建立全文索引
FULLTEXT KEY information (information)
)
使用ALTER TABLE 命令去增加索引
#建立联合索引
ALTER TABLE user ADD INDEX sname (first_name,last_name)
#建立外键
ALTER TABLE user ADD UNIQUE KEY id_card (id_card)
#建立全文索引
ALTER TABLE user ADD FULLTEXT KEY information (information)
CREATE INDEX 命令创建
ALTER TABLE user ADD INDEX(id_card(2)):前缀索引,以前两位字符创建索引
删除索引
ALTER TABLE user DROP KEY sname
ALTER TABLE user DROP KEY id_card
ALTER TABLE user DROP KEY information
#先取消自增再删除主键索引
ALTER TABLE user MODIFY id int,DROP PRIMARY KEY
数据库三范式
第一范式:保证数据库表的列是不能分割的,即保证其原子性
一张表中存储了员工id,部门id,员工信息(姓名、年龄、住址)、员工部门
为了满足第一范式:需要将员工信息的字段单独作为一列
即:表: 员工id,部门id,姓名、年龄、住址、员工部门
第二范式:在第一范式基础上,字段完全依赖于主键(消除了部分依赖)
比如:一张表中存储了员工id,部门id,姓名、年龄、住址、员工部门
此时:主键可以为(员工id+部门id),员工部门依赖于部门id;员工信息依赖于员工id,产生了部分依赖
为了满足第二范式:需要拆分为两张表:
- 员工表:员工id、姓名、年龄、住址
- 部门表:部门id、员工部门
第三范式:在第二范式基础上,表中的每一列只与主键直接相关而不是间接相关(可以通过非主属性追溯到另一个属性),表中的每一列只能依赖于主键,消除传递依赖
比如Student表(学号,姓名,年龄,性别,所在院校,院校地址,院校电话)
学号—>所在院校—>院校地址
学生表(学号,姓名,年龄,性别,所在院校)
院系表(所在院校,院校地址,院校电话)
mysql主要存储引擎
SHOW ENGINES 可以查询mysql的存储引擎
MyISAM:
- MyISAM这种存储引擎不支持事务,支持全文索引,适合大量的查询操作,采用表锁,是非聚簇索引,索引保存的是数据文件的指针;
- MyISAM会在磁盘上存储成三个文件
- frm文件:存储文件的格式
- MYD文件:存储文件的数据
- MYI文件:存储索引
- 该存储引擎通过MYI的B+树结构来查找记录页,再根据记录页查找记录。并且支持全文索引、B树索引和数据压缩。
MyISAM存储引擎在执行查询语句(SELECT),会自动给涉及的所有表加读锁(共享锁),在执行更新操作(UPDATE、DELETE、INSERT等),会自动给涉及的表加写锁(排他锁),这个过程并不需要用户干预。
InnoDB:mysql默认的存储引擎
- 支持事务,支持外键,默认是行锁,是聚簇索引,索引和数据文件是在一起的(通过主键索引效率很高),适合增删改操作
- 表的结构存储在frm文件中,数据存储在表空间(ibd文件)
sql的约束
- NOT NULL 非空约束:保证列中数据不能有 NULL 值
- DEFAULT 默认 约束:提供该列数据未指定时所采用的默认值
- UNIQUE 唯一约束:保证列中的所有数据各不相同
- 主键约束:唯一标识数据表中的行/记录
- 外键约束:唯一标识其他表中的一条行/记录
- CHECK 约束:此约束保证列中的所有值满足某一条件
mysql中char和varchar的区别
char是一个定长字段,varchar是可变长的字段;
如果确定了某个字段的长度,可以使用char,不确定则使用varchar
mysql中in和exists区别
exists关键字后面跟一个任意的子查询,系统对子查询进行判断是否返回行,如果至少返回一行,那么exists为true,此时外层的查询语句执行;如果子查询没有任何的返回行,匿名exists为false,此时外层查询语句不会执行;
in关键字后面也是一个子查询,内查查询会返回一个数据列;
区别:
-
in是把外表和内表做hash连接,先查询内表;exists是对外表做loop循环,循环后在对内表查询;
-
当查询两个表的数据量相当时,使用exits或者in都可
-
当两个表中一大一小时,如果子查询是大,那么用exists;如果子查询是小,用in
mysql drop delete truncate区别
(
mysql 执行查询过程
事务
事务就是一组原子性的操作,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
事务的四个特性
- 原子性:操作要么都成功,要么都失败
- 一致性:事务从一种一致性状态转为另一种一致性的状态;即在操作前后数据的总量不变
- 隔离性:多个事务之间互不影响
- 持久性:事务处理的结果都是持久的,把数据存储到磁盘
脏读、不可重复读、幻读
在并发的情况下会导致数据出现问题:
脏读:事务A读取到事务B更新的数据,然后事务B回滚(未提交),事务A读到的数据就是脏数据
不可重复读:事务A多次读取同一个数据,事务B在事务A读取数据的过程中,对数据做了修改并且提交,导致事务A多次读取同一数据时,结果不一致;
幻读:事务A在查询数据时,事务B在事务A查询数据的过程中插入了一条数据并且提交,查询后,此时事务A发现多出来一条数据,仿佛幻觉一样
事务的隔离级别
隔离级别:
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
---|---|---|---|
未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
已提交读(Read committed) 解决脏读 | 不可能 | 可能 | 可能 |
可重复读(Repeatable read解决不可重复读(mysql默认) | 不可能 | 不可能 | 可能 |
可串行化(Serializable )解决幻读 | 不可能 | 不可能 | 不可能 |
事务的隔离机制的实现是基于锁机制和并发调度,并发调度使用的是MVCC实现的
事务的实现原理
事务操作过程:
- 开启事务
- 业务操作
- 是否有异常
- 有异常,事务回滚
- 无异常,事务提交
事务是基于重做日志(redo log)和 回滚日志(undo log)实现的。每次提交一个事务必须先将该事务的所有日志写入到重做日志文件进行持久化,数据库通过redo log 来保证事务的原子性和持久性
每当修改数据的时候,还会产生undo log(记录的反向的sql语句),如果需要回滚,则根据undo log里的反向语句进行逻辑操作。比如insert在undo log里记录的是delete;undo log保证数据的一致性
mysql的事务日志
InnoDB的事务日志:redo log和undo log
Redo log
redo log包括两部分:一是内存中的日志缓冲(redo log buffer
),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log
file),该部分日志是持久的。
- 事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲。
- 在事务提交之前,缓冲的日志都需要提前刷新到磁盘上持久化,这就常说的“日志先行”(Write- Ahead-Logging)。
- 此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据 redo log 中记录的日志,把数据库恢复到崩溃前的一个状态
在系统启动的时候,就已经为 redo log 分配了一块连续的存储空间,以顺序追加的方式记录 Redo Log,通过顺序 IO 来改善性能。所有的事务共享 redo loge 的存储空间,它们的 Redo Log 按语句的执行顺序,依次交替的记录在一起。
Undo log
undo log有两个作用:提供回滚和多个行版本控制(MVCC)。
undo log
和redo log
记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。
Binlog
Binlog 是 server 层的日志,即使是数据的存储的日志(可以理解成业务日志)。主要记录数据库表结构的变更(create、alter)以及表数据的更改(insert、update、delete)的二进制日志。
在实际应用中,主要用在两个场景:主从复制和数据恢复
- 主从复制场景:在 Master 主端开启 Binlog,将 Binlog 发生到各个 Slave 从端,Slave 从端重放 Binlog 从而达到主从数据一致
- 数据恢复场景:通过使用 mysqlbinlog 工具来恢复数据
什么是MVCC?
mvcc:multi-version-concurrent-control 即多版本并发控制,是通过保存数据在某个时间点的快照来实现的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据是不同的
MVCC只在读取已提交(Read Committed)和可重复读(Repeatable Read)两个事务级别下有效
MVCC实现原理
通过Undo日志中的版本链和ReadView一致性视图来实现的。MVCC就是在多个事务同时存在时,SELECT语句找寻到具体是版本链上的哪个版本,然后在找到的版本上返回其中所记录的数据的过程。
表中有三个隐藏的列:
- ROW ID: 隐藏的自增id,如果表没有主键,InnoDB会自动按照ROW ID来创建一个索引树
- 事务 ID:记录最后一层修改该记录的ID
- 回滚指针:通过它可以将不同的版本串联起来,形成版本链。相当于链表的next指针。
假设现在有一张account表,其中有id和name两个字段,那么版本链的示意图如下
优点:
- 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能
- 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新丢失问题
数据库的锁
行锁(InnoDB):
- 行锁是mysql中锁粒度最细的一种锁,表示只针对当前操作的行加锁。行锁可以大大减少数据库操作的冲突,行锁分为共享锁(读锁)和排它锁(写锁)
- 开销大,加锁慢,会出现死锁
表锁(MyISAM):
- 表锁是mysql中锁粒度最大的一种锁,表示对当前操作的整张表加锁,实现简单,资源消耗少,被大部分的mysql存储引擎支持。MyISAM和InnoDB都支持表锁。表锁也分为共享锁(读锁)和排它锁(写锁)
- 开销小,加锁块,不会出现死锁
页级锁(BDB引擎):底层存储是按页的(块)
- 页级锁介于行锁和表锁之间,一次锁定相邻的一组记录,
- 会出现死锁
共享锁(读锁):
当用户对数据进行读取时加读锁,读锁可以同时加上多个,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
排它锁(写锁):
排他锁就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。
悲观锁:
顾名思义就是很悲观,每次操作数据的时候都认为别人会修改,所在对数据进行操作之前先上锁,在上锁期间其它人不能操作数据,直到释放锁
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁,java 中的 synchronized 和 ReentrantLock 也是悲观锁的思想。
乐观锁:
顾名思义就是很乐观,每次操作数据的时候都认为别人不会修改,所以默认是不会上锁的,只有当数据更新时才会判断别人有没有修改数据,如果修改了就操作失败。
乐观锁的实现机制有:CAS和版本号机制
InnoDB的行锁是怎么实现的
InnoDB是基于索引来完成行锁,
例: select * from tab_with_index where id = 1 for update;
for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将完成表锁,并发将无从谈起
死锁
死锁就是:多个线程被同时阻塞,他们中的一个或多个都在等待某个资源的释放,导致线程被无限的阻塞,程序不能正常终止

死锁产生的四个必要条件:
- 互斥条件:共享资源任意时刻只能被一个线程占有
- 不可剥夺条件:资源的请求者不能强行从资源的占有者抢夺资源,只能等待资源占有者主动释放
- 请求与保持条件:资源的请求者在请求其它资源的同时,保持对原有资源的占有
- 循环等待条件:即存在一个循环等待队列:p1要p2的资源,p2要p1的资源
如何解决死锁:打破在四个条件中的一个即可
- 互斥条件:这个不能打破,共享资源本身就是互斥访问的
- 不可剥夺条件:可以打破,如果一个线程持有部分资源,在请求不到其它资源时,立即释放持有的资源,供其它线程使用
- 请求与保持条件:可以打破,在申请资源时一次性申请所有需要的资源,这样就不用去请求其它资源
- 循环等待条件:按照特定的申请资源的顺序
隔离级别与锁的关系
- 读未提交:读取数据不需要加共享锁
- 读已提交:读操作需要加共享锁,但是在语句执行完成后会释放锁
- 可重复读:读操作需要加共享锁,但是必须等待事务提交之后才会释放锁
- 可串行化:最强的隔离级别,锁定整个范围的键,并一直持有锁,直到事务完成
分库分表
为什么需要分库分表?
分表:
单表的数据量太大,会极大的影响sql执行的性能;分表就是把一个表的数据放到多个表中,然后查询的时候就查一个表。
分库:
将一个库的数据拆分到多个库中,访问的时候就访问一个库就好了
(
分库分表的方式
垂直拆分
- 垂直分库:按照业务来拆分,比如一个电商系统,把订单、普通用户、会员、商品都单独作为一个库

- 垂直分表:垂直分表是基于数据库中的"列"进⾏,某个表字段较多,可以新建几张扩展表,将不经常⽤或字段 ⻓度较⼤的字段拆分出去到扩展表中。
特点:
- 每个库(表)的结构都不一样
- 每个库(表)的数据都不一样(每个库表都包含部分字段)
- 每个库(表)的并集是总量数据
优点:
- 拆分后业务清晰、数据维护简单
缺点:
- 如果单表的数据量大,读写压力会很大(单个业务读写数据量大)
- 受某种业务决定,或者被限制,也就是说一个业务往往会影响到数据库的瓶颈(性能问题)
- 部分业务无法关联join,只能通过java程序接口去调用,提高了开发复杂度
水平拆分
- 水平分库:以id拆分,按照数量平均给;根据id最后一位奇偶来拆分:就是把数据平均分
- 水平分表:根据规则把表拆分多个表,表中数据比例是差不多的
优点:
- 单库/单表的数据保持在一定量(减少),有助于性能提高
- 提高了系统的稳定性和负载能力
- 拆分表的结构相同,程序改造较少
缺点:
- 数据的扩容很有难度维护量大
- 拆分规则很难抽象出来(就是很难选择以哪个场景来拆分—因为业务是非常复杂的)
- 分片事务的一致性问题部分业务无法关联join,只能通过java程序接口去调用
分库分表的问题
- 分布式事务
- 跨库join查询
- 分布式全局唯一id
- 开发成本 对程序员要求高
读写分离、主从复制
什么是读写分离和主从复制
读写分离:顾名思义就是将数据库的读和写分开,主数据库(Master)负责写操作,从数据库(Slave)负责读操作。
主从复制:把主数据库(Master)的数据复制到从数据库(Slave)。就是主数据库出现了变化,其它的从数据库也要相应的发生改变(一主多从)
优点:
- 安全。主库故障,可以快速切换至从库提供服务;
- 提高性能。在从库执行查询操作,降低主库的访问压力,提高数据库的并发性能;
- 数据备份。在从库执行备份,避免备份期间对主库影响;
主从复制的流程和原理
- 主库—binlog线程:会记录所有改变了数据库数据的语句,放在主库的binlog,当Master的binlog发生变化时,binlog dump线程会通知所有的slave节点,并且将变化的binlog也推送到slave节点中
建立连接时,Master会根据Slave的数量来创建binlog dump线程
- 从库—IO线程:io线程会接收binlog的内容,将内容写入到本地的relay-log中。
- 从库—Sql线程:读取relay-log,根据其内容对从数据库做出对应的操作
主从复制的类型
- 基于语句的复制 (SBR:Statement-base Replication):在Master上执行的sql语句,在Slave上也执行相同的语句
- 基于行的复制 (RBR:row-based replication):把改变的内容复制到Slave
- 混合类型的复制 (MBR:mixed-based replication):默认采用语句复制,当发现语句无法精准复制时,改用基于行复制(一般情况都使用这种方式,让mysql自动选择)
mysql主从同步延时问题
主从延迟,就是同一个事务,从库执行完成的时间与主库执行完成的时间之差,也就是 T3 - T1
。
- 主库执行完一个事务,写入 binlog,将这个时刻记为 T1;
- 之后传给从库,将从库接收完这个 binlog 的时刻记为 T2;
- 从库执行完成这个事务,将这个时刻记为 T3。
在从服务器上通过 show slave status 查看具体的参数
- 半同步复制:指主库写入binlog日志后,就会强制此时立即将数据同步到从数据库,直到从库返回ack信息给主库,才算完成
- 并行复制:从库开启多个线程,并行读取relay log中不同库的日志,如何并行重新放入不同库的日志
MySQL 有三种同步模式,分别是:
「异步复制」:MySQL 默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给客户端,并不关心从库是否已经接收并处理。这样就会有一个问题,一旦主库宕机,此时主库上已经提交的事务可能因为网络原因并没有传到从库上,如果此时执行故障转移,强行将从提升为主,可能导致新主上的数据不完整。
「全同步复制」:指当主库执行完一个事务,并且所有的从库都执行了该事务,主库才提交事务并返回结果给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。
「半同步复制」:是介于全同步复制与全异步复制之间的一种,主库只需要等待至少一个从库接收到并写到 Relay Log 文件即可,主库不需要等待所有从库给主库返回 ACK。主库收到这个 ACK 以后,才能给客户端返回 “事务完成” 的确认。
mysql调优
慢查询如何优化
慢查询有很多的原因,是数量太大了、还是加载了不需要的数据列,最常见的就是没有加索引或者没有使用索引
开启慢查询日志:在my.cnf文件修改值为1
- 查看慢查询的日志,定位到查询慢的语句(show variables like '%slow_query_log%')
- 分析sql语句,看看是否加载了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写
- 使用explain分析sql语句,然后查看(type:最)是否使用了索引,使语句尽可能的命中索引
- 如果对语句已经不能优化了,数据量很大,可以考虑分表
mysql语句的执行顺序
from—>on(连接条件)—>join—>where—>groupby—>聚合函数—>having(对分组之后的数据再次过滤)—>distinct(去重)—>select—>orderby(排序)—>limit
mysql如何优化查询过程中数据访问
- 查询不需要的数据,使用limit指定查询数据
- 多表关联返回全部列,通过指定列名
- 总是返回全部列,避免使用:select *
- 重复查询相同的数据,可以缓存数据
- 改变数据库和表的结构
- 重写sql语句,让优化器以更优的方式执行查询
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!