MySQL 面试题

161 阅读27分钟

mysql 有那些存储引擎,有哪些区别

myisam

  • 不支持事务,没有redo log

  • 支持表级别锁

  • 支持全文索引

  • 不支持MVCC

  • 存储引擎为 B Tree

innodb

  • 支持事务,有redo log

  • 支持行级锁

  • 支持全文索引

  • 支持MCVV

  • 存储引擎为 B+ Tree

memory

  • 不支持TEXT和BLOB类型。对于字符串类型的数据,只支持固定长度的行,VARCHAR(64)会被自动存储为CHAR(64)类型

  • 只支持表级锁

  • 数据存储在内存中,易丢失

  • 查询的时候,有用到临时表,而临时表中有BLOB,TEXT类型的字段,那么这个临时表会转化为MyISAM的表,性能急剧降低

  • 默认hash索引

online DDL

  • 拿MDL写锁

  • 降级成MDL读锁

  • 真正做DDL

  • 升级成MDL写锁

  • 释放MDL锁

参考资料

DDL, DML, DCL 和TCL是什么?

DDL (Data Definition Languages)

即数据库定义语句,用来创建数据库中的表、索引、视图、存储过程、触发器等

常用的语句关键字有:CREATE,ALTER,DROP,TRUNCATE,COMMENT,RENAME

DML(Data Manipulation Language)

即数据操纵语句,用来查询、添加、更新、删除等

常用的语句关键字有:SELECT,INSERT,UPDATE,DELETE,MERGE,CALL,EXPLAIN PLAN,LOCK TABLE,包括通用性的增删改查

DCL(Data Control Language)语句

即数据控制语句,用于授权/撤销数据库及其字段的权限

(DCL is short name of Data Control Language which includes commands such as GRANT and mostly concerned with rights, permissions and other controls of the database system.)

常用的语句关键字有:GRANT,REVOKE

TCL(Transaction Control Language)

事务控制语句,用于控制事务

常用的语句关键字有:COMMIT,ROLLBACK,SAVEPOINT,SET TRANSACTION

mysql 索引在什么情况下会失效

函数计算导致索引失效

  • B+ Tree的快读定位,来源于同一层兄弟节点的有序性

  • 而函数计算得出的结构,无法在树中快速定位

  • 对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能

隐式类型转换

  • MySQL 默认是把字符串转换成数字

  • 当遇到将数字转换成字符串的情况,就类型加上了一个函数操作。导致需要全局搜索

隐式字符编码转换

  • 两个表的字符集不同。一个是utf8,一个是utf8mb4,所以做表连接查询用不上关联字段索引

  • 因为字符集不同,需要转换成相同的字符串,就需要用到CONVERT() 函数。所以放弃走树搜索功能

存在or条件语句

  • 如果条件中有or,即使其中有条件带索引也不会使用

最左前缀原则

  • 最左前缀可以是联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符。其实也就是索引的顺序,频繁搜索放在最左

  • 使用多个条件或 like 'x%' 搜索的时候。如果不符合最左前缀原则,会导致索引无效

参考资料

mysql 的索引模型

二叉查找树

  • 二叉查找树的特点:父节点左子树所有节点的值小于父节点的值,右子树所有结点的值大于父节点的值

B Tree (M阶B树)

image.png

  • 根节点至少有两个子女

  • 每个中间节点都包含k - 1个元素和k个孩子,其中 m / 2 <= k <= m

  • 每一个叶子节点都包含k - 1个元素, 其中 m / 2 <= k <= m

  • 所有的叶子节点都位于同一层

  • 每个节点的元素从小到大排列,节点当中 k - 1个元素正好是k个孩子包含的元素的值域分划

卫星数据

指的是索引元素所指向的数据记录,比如数据库中的某一行

在B 树中,无论中间节点还是叶子节点都带有卫星数据

B+ Tree(M阶B+树),与B Tree的不同点

image.png

  • B+ 和 B树有一些共同点,但B+树也具备新的特征

  • 有k个子树的中间节点包含有k个元素(B树中是k - 1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点

  • 所有叶子节点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子节点本身依关键字的大小自小而大顺序链接

  • 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素

  • 而在B+ 树当中,只有叶子节点带有卫星数据,其余中间节点仅仅是索引,没有任何数据关联

B+ 树的优势

  • 单一节点存储更多的元素,使得查询IO次数更少

  • 所有查询都要找到叶子节点,查询性能稳定

  • 所有叶子节点形成有序链表,便于范围查询

参考资料

Innodb 数据页结构

数据页结构(16KB)

| 名称 | 中文名 | 占用空间 | 简单描述 |

| --- | --- | --- | --- |

| File Header | 文件头部 | 38字节 | 页的一些通用信息 |

| Page Header | 页面头部 | 56字节 | 数据页专用的一些信息 |

| Infimum + Supremum| 最小记录和最大记录| 26字节| 两个虚拟的行记录|

| UserRecodes | 用户记录 | 不确定 | 实际存储的行记录内容 |

| Free Space | 空闲记录 | 不确定 | 页中尚未使用的空间 |

| Page Directory | 页面目录 | 不确定 | 页中的某些记录的相对位置 |

| File Trailer | 文件尾部 | 8字节 | 校验页是否完整 |

  • 各个数据页之间可以组成一个双向链表

  • 每个数据页中又是一个单向链表

  • 在通过主键查找某条记录的时候可以在页目录二分法快速定位到对应槽,然后再遍历该槽对应分组中的记录即可得到指定的记录

  • 以其他列作为搜索条件:只能从最小记录开始依次遍历单链表中的每条记录

Compact行格式

  • 变长字段长度列表: varchar(M)、varbinary(M)、text、blob

  • NULL 值列表: 把NULL统一管理起来

  • 记录头信息

基于页结构管理

在硬盘中存储以页为组织单位的索引树,查找a > 10的数据,先从已经预加载到内存的根页开始判断,看看相关数据需要到哪一个子页去找,定位好了子页,进行一次IO操作

根据地址将指向这个子页从硬盘中读取到内存中,这是一次IO操作,因为B+树是以页为组织单位,一页会有很多数据,而且还是一个多叉树,就会使树的高度很低,树的高度变低就会使用IO操作大大减少

因为大量操作已经内存中的页里完成了,也就大大减少了IO操作,提高了数据的检索效率

参考资料

binlog 日志是 master 推的还是 slave 来拉的?

主库上会有一个 dump_thread 读取binlog 日志发送给从库

mysql 主从同步怎么搞的?

主从流程

  • 主库上的 dump_thread,会将binlog event 传到 从库,让io_thread接收

  • 在从库上设置从库的ID,ID要唯一

  • 从库上通过 change master命令,设置主库的IP、端口、用户名、密码、要从哪个位置请求binlog(文件名、日志偏移量)

  • 在从库上执行start slave时,会启动两个线程, io_thread、sql_thread

  • io_thread 负责与主库建立连接(长连接)。主库校验完用户名、密码,开始按照从库传来的位置,从本地读取binlog ,发给从库

  • 从库B拿到binlog后,写到本地文件,称为中转文件(relay log)

  • sql_thread读取中转日志,解析出日志里的命令,并执行

图例

image.png

参考资料

怎么判断主从延迟

备库上执行 show slave status 命令,它的返回结果里面会显示 seconds_behind_master,用于表示当前备库延迟了多少秒

seconds_behind_master 的计算方法是这样的:

  • 每个事务的 binlog 里面都有一个时间字段,用于记录主库上写入的时间

  • 备库取出当前正在执行的事务的时间字段的值,计算它与当前系统时间的差值,得到 seconds_behind_master

乐观锁与悲观锁的区别?

乐观锁

乐观锁认为并发冲突是不常见的,所以在操作数据时不会加锁,而是在更新数据时判断数据是否被其他线程修改过

如果数据没有被修改,则更新成功,否则回滚并重试更新操作,这种机制被称为“乐观锁”

在MySQL中,乐观锁可以使用版本号或者时间戳来实现。例如,使用时间戳实现乐观锁


UPDATE table SET column = value, update_time = now() WHERE id = ? AND update_time = ?

悲观锁

悲观锁则相反,它认为并发冲突是常见的,所以在操作数据时会先加锁,其他线程需要等待锁被释放才能访问数据

在MySQL中,悲观锁可以使用SELECT ... FOR UPDATE或者SELECT ... LOCK IN SHARE MODE来实现。例如,使用SELECT ... FOR UPDATE实现悲观锁


START TRANSACTION;

SELECT column FROM table WHERE id = ? FOR UPDATE;

UPDATE table SET column = value WHERE id = ?;

COMMIT;

总结

乐观锁适用于读多写少的情况,因为数据冲突的概率比较小

悲观锁适用于写多读少的情况,因为多个线程同时写入数据的概率比较大

参考资料

binlog 日志和 redolog 日志清楚吗? 两阶段提交和组提交

Write-Ahead Logging(WAL)

先写日志,后写磁盘

redolog

Innodb的redo log是固定大小的,一组4个文件,每个文件大小1G

redo log日志格式

  • type : redo log 存在多种日志格式。主要是节省内存空间

  • Space ID: 表空间ID

  • Page Number: 数据页ID。通过表空间ID和数据页ID,可以唯一表示一个数据页

  • offset: 偏移量

  • len: 长度

  • data: 就是对该数据页到底做了哪些修改(redo log block 结构)

redo log block 结构

  • log block header

  • LOG_BLOCK_HDR_NO: 4字节,每一个block都有一个大于0的唯一标号,本属性就表示该标号值

  • LOG_BLOCK_HDR_DATA_LEN: 2字节,表示block中已经使用了多少字节,初始值为12,随着往block中写入的redo日志越来也多,本属性值也跟着增长

  • LOG_BLOCK_FIRST_REC_GROUP: 2字节,一条redo日志也可以称之为一条redo日志记录,一个mtr会生产多条redo日志记录,这些redo日志记录被称之为一个redo日志记录组

  • LOG_BLOCK_CHECKPOINT_NO: 4字节,表示所谓的checkpoint的序号

  • log block body

  • log block tailer

  • LOG_BLOCK_CHECKSUM: 4字节

redo log block "存放redo log的小池子",只有512B

在innodb_buffer_pool的data page里做update操作。并把操作的物理数据页修改到redo log buffer里

由于update 这个事物会涉及到多个页面的修改,所以redo log buffer 会记录多条页面的修改信息

因为group commit的原因,这次事物所产生的redo log buffer可能会跟随其他事务一同flush并且 sync到磁盘上

binlog

Statement格式

  • 记录每一条数据的SQL,将执行的的每条sql记录在binlog中

  • 缺点:1. 可能导致主备选择的索引不一致

Row格式

  • binlog 记录的是操作数的字段值,根据binling_row_image的默认配置是FULL包括操作行为的所有字段值

  • binlog_row_iamge 设置为MINNMAL,则会记录必须的字段

Mixed格式

  • 因为有些statement 格式的binlog可能会导致主备不一致,所有要使用row格式

  • 但row格式的缺点是,很占空间。比如你用一个delete语句删除10万行数据,用statement的话就是一个SQL语句记录到binlog中,占用几十个字节的空间。但如果用row格式的binlog,就要把着10万条记录都写到binlog中。这样做不经会占用更大的空间,同时写binlog也会耗费IO资源,影响执行速度

  • 所以,就有了mixed格式。mixed格式的意思是,MYSQL自己会判断这条SQL是否可能引起主备不一致,如果有可能,就用row格式,否则就用statement格式

二阶段提交

先写 redo log 再写binlog

Prepare阶段

  • redolog 先处于 Prepare阶段时把数据写入 redolog buffer中,这个时候binlog 也把数据写入到binlog_cache.同时flush到操作系统的Page cache

  • 将redolog buffer,binlog_ache fsync 到磁盘文件上中

Commit阶段

  • 由于之前该事务产生的redo log已经fsync已经磁盘,这里在redolog标记commit

日志逻辑序列号(LSN)

在innodb引擎中,lsn占8个字节。lsn是单调递增的

根据LSN,可以获取到几个有用的信息

  • 数据页的版本信息

  • 写入的日志总量,通过LSN开始号码和结束号码可以计算出写入的日志量

  • 可知道检查点的位置

LSN的作用

  • 首先修改内存中的数据页,并在数据页中记录LSN,暂且称之为data_in_buffer_lsn

  • 并且在修改数据页的同时(几乎是同时)向redo log in buffer中写入redo log,并记录下对应的LSN,暂且称之为redo_log_in_buffer_lsn

  • 写完buffer中的日志后,当触发了日志刷盘的几种规则时,会向redo log file on disk刷入重做日志,并在该文件中记下对应的LSN,暂且称之为redo_log_on_disk_lsn

  • 数据页不可能永远只停留在内存中,在某些情况下,会触发checkpoint来将内存中的脏页(数据脏页和日志脏页)刷到磁盘,所以会在本次checkpoint脏页刷盘结束时,在redo log中记录checkpoint的LSN位置,暂且称之为checkpoint_lsn

  • 要记录checkpoint所在位置很快,只需简单的设置一个标志即可,但是刷数据页并不一定很快

  • 例如这一次checkpoint要刷入的数据页非常多

  • 也就是说要刷入所有的数据页需要一定的时间来完成,中途刷入的每个数据页都会记下当前页所在的LSN,暂且称之为data_page_on_disk_lsn

组提交

如存在三个并发事务(trx1、trx2、trx3)在prepare阶段,都写完redolog buffer,持久化的过程,对应LSN为50、120、160

trx1第一个达到,会选为这组的组长

等 trx1 要开始写盘的时候,这个组里面已经有了三个事务,这时候 LSN 也变成了 160

trx1 去写盘的时候,带的就是 LSN=160,因此等 trx1 返回时,所有 LSN 小于等于 160 的 redo log,都已经被持久化到磁盘

这时候 trx2 和 trx3 就可以直接返回了

参考资料

MySQL 如何分析一条语句的执行过程。delete from t1 limit 3和delete from t1的区别?

表删除的流程

首先要经过连接器,对账号和密码和权限进行验证

词法分析器对delete、表名、字段、where等关键字进行检测。语法分析判断表名、字段或附带的条件的存在进行检查

优化器执行计划生成,选择适当的索引

打开innodb 存储引擎。把删除语句写入redo log 和 binlog。redo log 是为了做崩溃恢复,binlog是主从同步

  • redo log具体记录的就是表空间号,数据页号,偏移量,修改了几个字节的值和具体的修改值

  • 二阶段提交,保证redo log和binlog都写入了信息

然后看看,删除语句的条件里是否带主键索引还是二级索引。如果主键索引就要立即执行,如果是二级索引,记录存储在change buffer中,然后异步执行

在硬盘中存储以页为组织单位的索引树,从根页开始判断,根据要执行的语句,选择好子页。然后进行删除

当执行delete语句时,Inndb做标记删除;如果后续插入数据时,定位到这个数据页上有可能继续复用这个位置

同理,如果一个数据页上的数据都被删除了, 那么这个数据页也是可以被复用的

delete from t1 limit 3和delete from t1的区别?

一个只锁3条记录,一个会锁全表。删除的每行加行锁,间隙会加间隙锁

MySQl如果出现了死锁,你怎么排查,怎么判断出现了死锁?

show engine innodb status

  • 最近一次死锁日志

  • 查看造成死锁的sql语句

select * from information_schema.innodb_locks;

  • 查看锁情况

information_schema.innodb_lock_waits

  • 查看等待中的锁

information_schema.innodb_trx

  • 查看申请的锁的事务

  • 找出对应的SQL语句和线程ID

然后通过kill 来杀死线程ID

参考资料

事务的其特性有哪些?mysql是否支持嵌套事务?

事务的特性

A (Atomicity) 原子性

  • 一个事务中的操作,要么全部完成,要么全部不完成

C (Consistency) 一致性

  • 事务开始之前和事务结束后,数据库的完整性没有被破坏

I (Isolation) 隔离性

  • 数据库允许多个并发事务同时对数据进行读写和修改的能力

D (Durability) 持久性

  • 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

隔离级别

读未提交:一个事务还没提交时,它做的变更就能被别的事务看到

读提交:一个事务提交之后,它做的变更才会被其他事务看到

可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的

串行化: “写”会加“写锁”,“读”会加“读锁”

隔离性弱可能出现的问题

脏读:读到其他事务未提交的数据

不可重复读:前后读取的记录内容不一致

幻读:前后读取的记录数量不一致

主键索引和唯一索引的区别

主键是一种约束,唯一索引是一种索引,两者在本质上是不同的

主键创建后一定包含一个唯一性索引,唯一性索引并不一定就是主键

唯一性索引列允许空值,而主键列不允许为空值

主键列在创建时,已经默认为空值 + 唯一索引了

主键可以被其他表引用为外键,而唯一索引不能

一个表最多只能创建一个主键,但可以创建多个唯一索引

主键更适合那些不容易更改的唯一标识,如自动递增列、身份证号等

如何排查和优化查询比较慢的sql语句?

  1. 通过explain 可以查看一条SQL使用哪些索引和有什么使用临时表

EXPLAIN输出字段

id: 执行编号,标志select所属的行

select_type: 显示本行是简单或复杂select

table: 访问引用哪个表

type: 数据访问/读取操作类型

possible_keys: 解释哪一些索引可能有利用高效的查询

key: 显示mysql决定采用哪个索引来优化查询

key_len: 显示mysql在索引里使用的字节数

ref: 示了之前的表在key列记录的索引中查找值所用的列或常量

rows: 为了找到所需的行而需要读取的行数,估算值,不精确

Extra: 额外信息,如using index、filesort 等

  1. 如果语句执行的时候被卡住,通过show processlist,查看语句是否在等MDL锁

锁机制

image.png

共享锁与排他锁

InnoDB 实现了标准的行级锁,包括两种:共享锁(简称 s 锁)、排它锁(简称 x 锁)

  • 共享锁(S锁):允许持锁事务读取一行。

  • 排他锁(X锁):允许持锁事务更新或者删除一行

image.png

意向锁

意向共享锁( IS 锁):事务想要获得一张表中某几行的共享锁

意向排他锁( IX 锁): 事务想要获得一张表中某几行的排他锁

比如:

  • 事务1在表1上加了S锁后,事务2想要更改某行记录,需要添加IX锁,由于不兼容,所以需要等待S锁释放

  • 如果事务1在表1上加了IS锁,事务2添加的IX锁与IS锁兼容,就可以操作,这就实现了更细粒度的加锁

InnoDB存储引擎中锁的兼容性如下表

image.png

记录锁(Record Locks)

  • 记录锁是最简单的行锁,仅仅锁住一行。如:SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE

  • 记录锁永远都是加在索引上的,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁

  • 会阻塞其他事务对其插入、更新、删除

间隙锁(Gap Locks)

  • 间隙锁是一种加在两个索引之间的锁,或者加在第一个索引之前,或最后一个索引之后的间隙

  • 使用间隙锁锁住的是一个区间,而不仅仅是这个区间中的每一条数据

  • 间隙锁只阻止其他事务插入到间隙中,他们不阻止其他事务在同一个间隙上获得间隙锁,所以 gap x lock 和 gap s lock 有相同的作用

Next-Key Locks

Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁

插入意向锁(Insert Intention)

  • 插入意向锁是在插入一行记录操作之前设置的一种间隙锁,这个锁释放了一种插入方式的信号,亦即多个事务在相同的索引间隙插入时如果不是插入间隙中相同的位置就不需要互相等待

  • 假设有索引值4、7,几个不同的事务准备插入5、6,每个锁都在获得插入行的独占锁之前用插入意向锁各自锁住了4、7之间的间隙,但是不阻塞对方因为插入行不冲突

锁模式兼容矩阵(横向是已持有锁,纵向是正在请求的锁)

image.png

数据库中的事务是什么?

事务就是要保证一组数据库操作,要么全部成功,要么全部失败。事务的支持是在引擎层实现

事务的特性: 原子性、一致性、隔离型、持久性(ACID)

事务的隔离级别: 读未提交、读提交、可重复读、串行化

事务的实现: 每条记录在更新的时候都会同时记录一条回滚操作。同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制

索引优化

选择合适的索引类型

在MySQL中,有多种类型的索引,如B-tree索引、哈希索引、全文索引等

在创建索引时,需要根据具体的业务场景和查询方式选择最合适的索引类型

比如,如果需要进行模糊查询,就可以选择使用全文索引,而如果需要快速定位某个值,就可以选择使用B-tree索引

对经常使用的字段创建索引

在MySQL中,经常使用的字段应该创建索引,以提高查询效率

比如,对于经常用于where条件和join条件的字段,如用户ID、订单ID等,应该创建索引

但是,过多的索引也会影响查询效率,因此需要权衡利弊,选择最优的索引方案

避免在索引列上使用函数

在MySQL中,如果在索引列上使用函数,会导致索引失效,从而影响查询效率

因此,在设计数据库表结构时,应该尽量避免在索引列上使用函数,或者使用函数前对索引列进行计算,以避免影响索引效率

避免使用SELECT * 语句

在MySQL中,使用SELECT * 语句会导致查询所有字段,从而影响查询效率

因此,在编写查询语句时,应该明确指定需要查询的字段,避免使用SELECT * 语句

合理使用联合索引

在MySQL中,使用联合索引可以提高查询效率,但是需要注意联合索引的顺序和使用范围

如果联合索引中的前缀子集已经满足查询条件,就可以避免扫描整个联合索引,从而提高查询效率

定期优化数据库

定期进行数据库优化,包括清理无用数据、重新组织索引、更新统计信息等,可以提高数据库性能

在MySQL中,可以使用OPTIMIZE TABLE命令来重新组织表,使用ANALYZE TABLE命令来更新统计信息

参考资料

说一说Mysql的最左前缀匹配

MySQL的最左前缀匹配是指,在使用联合索引时,只有查询条件中最左边的索引列被使用了,后面的索引列将不会被使用。

这个规则可以适用于联合索引中的最左N个字段或字符串索引的最左M个字符

例如,如果有一个联合索引 (a, b, c),那么只有在查询条件中使用了 a 的情况下,才能利用这个索引进行优化

如果查询条件中使用了 a 和 b,但没有使用 c,则只能利用 a 和 b 这两个索引列进行优化,而不能使用 c 这个索引列

这个规则的应用可以帮助优化查询性能和减少索引的数量

mysql 字段怎么选择索引?

查询频率:选择经常作为查询条件的字段作为索引字段,比如经常用于筛选、排序或分组的字段

数据分布度:选择具有高度不重复值的字段作为索引字段可以提高索引的效果。如果某个字段的值具有高度不重复性,那么在使用该字段作为索引字段时,索引将可以更快地定位到具体的数据行

  • 一个索引上不同的值越多,这个索引的区分度就越好。比如关于性别的索引,数据就是男/女,数据区分度不高

  • 如果索引列的数据都相同,区分度低,按照该索引进行查询,有两种情况

  • b+叶子节点都满足查询条件,相当于全表扫描

  • b+叶子节点都不满足查询条件

  • 索引列数据都不同,区分度高,有3种情况

  • 有可能所有叶子结点满足查询条件

  • 部分b+ 叶子节点满足查询条件

  • b+叶子结点都不满足查询条件

数据类型:选择较小的数据类型作为索引字段可以减小索引的大小,提高查询性能。一般来说,整数类型的字段比字符串类型的字段更适合作为索引字段

  • 通过改变key值来调整

  • N叉树中非叶子节点存放的是索引信息,索引包含Key和Point指针

  • Point指针固定为6个字节

  • 假设Key为10个字节,那么单个索引就是16个字节

  • 如果B+树中页大小为16k,那么一个页就可以存储1024(1024叉树)个索引,此时N就等于1024.我们通过改变Key的大小,就可以改变N的值

  • 参数计算

  • result = 叶子节点数 * 一个叶子节点里能存放的数据条数

  • 叶子节点数 = 根节点的指针数 = {索引值+ 指针}组合数 = 索引值个数

  • 假设一行数据的大小-=1KB(合理的值)

  • 一个叶子节点能够存放的数据条数?16KB / 1KB = 16条

  • 索引值个数?16KB / {int类型索引值8B + 指针6B} (14B) = 16KB / 14B = 1170

  • result = 1170 * 16=18720

组合索引:如果查询中包含多个字段的筛选条件,可以考虑使用组合索引。组合索引是包含多个字段的索引,可以同时使用多个字段来定位数据

mysql 查询该怎么优化?

确保正确的索引:索引是加快查询速度的关键。通过为经常被查询的列创建索引,可以减少数据的扫描和比较,提高查询性能。在设计表结构时,考虑哪些列需要进行查询,并为这些列创建合适的索引

避免全表扫描:尽量避免在查询中使用不带WHERE子句的SELECT语句,这会导致全表扫描,影响性能。尽量使用索引来限制查询范围

减少查询返回的数据量:只返回需要的列,避免查询不必要的数据。可以使用SELECT语句的列名列表来指定需要返回的列,而不是使用通配符(*)查询所有列

使用JOIN优化:合理使用JOIN来连接多个表。使用JOIN时,确保连接字段上有索引,以避免性能瓶颈。

优化子查询:子查询可能会导致性能下降,可以考虑将子查询转换为JOIN操作来优化性能

使用EXPLAIN分析查询计划:通过使用EXPLAIN语句,可以查看MySQL优化器是如何执行查询的,从而帮助我们找到潜在的性能问题

避免使用SELECT *:查询时尽量避免使用SELECT *,只查询需要的列,可以减少传输的数据量,提高查询性能

避免在查询中使用函数:使用函数会导致索引失效,可以考虑在查询之前对数据进行处理,将结果存储在一个新的列中,然后再进行查询

定期优化表:使用OPTIMIZE TABLE语句可以优化表的结构,提高查询性能。此外,还可以定期进行表的统计信息收集,以便MySQL优化器做出更好的查询计划