学习 mysql实战45讲 笔记(1~10),用于后期检验

仅供自己复习用

 

第一章 mysql的结构,和查询语句流程

1. MySQL的框架有几个组件, 各是什么作用? 

 连接器,缓存器,分析器,优化器,执行器
2. Server层和存储引擎层各是什么作用?

server层提供核心组件的功能,同时提供视图,执行过程等和一些函数操作,引擎层主要对应数据的操作

3. you have an error in your SQL syntax 这个保存是在词法分析里还是在语法分析里报错?

语法分析,词法分析主要解析出sql语句中的字符串代表什么意思

4. 对于表的操作权限验证在哪里进行?

执行器中

5. 执行器的执行查询语句的流程是什么样的? 

比如要查询数据name=张三的语句

1.调用数据引擎的查询接口获取第一行数据,判断是不是张三,如果是则记录到结果集

2.获取下一行,执行上面的判断,一直到最后一行.

3.将上面执行所有满足条件的结果集返回给客户端.

针对索引也是差不多的,第一次取满足条件的第一行,之后取满足条件的下一行.

 

第二章 redolog binlog 修改语句执行流程

1. redo log的概念是什么? 为什么会存在.

重做日志,redolog是对记录修改之后的物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来崩溃恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。记录格式(数据文件、数据页、数据行、操作类型、操作值)

正常mysql修改数据时,要将操作写入磁盘,然后磁盘每次也需要找到对应的那条数据,这样io成本过高,当有数据更新操作时,innodb会先将数据记录在redo log中,并更新内存,在合适的时间再将操作写入磁盘.这里要注意 写数据不是把redo log写入,redolog只是为了保证crash safe,真正刷数据还是把内存中的脏页刷进去

.

redo log并没有记录数据页的完整数据,所以它并没有能力自己去更新磁盘数据页

如果是正常运行的实例的话,数据页被修改以后,跟磁盘的数据页不一致,称为脏页。最终数据落盘,就是把内存中的数据页写盘。这个过程,甚至与redo log毫无关系。

在崩溃恢复场景中,InnoDB如果判断到一个数据页可能在崩溃恢复的时候丢失了更新,就会将它读到内存,然后让redo log更新内存内容。更新完成后,内存页变成脏页,就回到了第一种情况的状态。

 

redo log是固定大小的,从头开始写,当写到末尾时会循环重头再来,其中存在write pos代表当前记录位置,同时ckeckpoint记录当前要擦除的位置,系统空闲时会将部分redolog操作记录到硬盘,同时更新checkpoint.

(

关于顺序写和随机写

第一种:假设我们所需要的数据是随机分散在磁盘的不同页的不同扇区中的,那么找到相应的数据需要等到磁臂(寻址作用)旋转到指定的页,然后盘片寻找到对应的扇区,才能找到我们所需要的一块数据,一次进行此过程直到找完所有数据,这个就是随机IO,读取数据速度较慢。

第二种:假设我们已经找到了第一块数据,并且其他所需的数据就在这一块数据后边,那么就不需要重新寻址,可以依次拿到我们所需的数据,这个就叫顺序IO。通俗点说就是追加写

)

2. 什么是WAL(write-ahead log)机制, 好处是什么.

先记录日志,再记录磁盘,执行事务的时候,写完内存和日志事务就算完成了,好处就是上面的redo log crash safe,同时,可以不需要每次更新都把内存中的数据实时刷入磁盘.减少IO

 

3. redo log 为什么可以保证crash safe机制.

crash safe,即当服务器突然断电或宕机,需要保证已提交的数据或修改不会丢失,未提交的数据能够自动回滚

Innodb通过Redo Log和Undo Log可以保证以上两点。为了保证严格的CrashSafe,必须要在每个事务提交的时候,将Redo Log写入硬件存储,通过redo日志将所有已经在存储引擎内部提交的事务应用redo log恢复到内存中.所有已经prepare但是没有commit的transactions将会应用undo log做rollback


4. binlog的概念是什么, 起到什么作用, 可以做crash safe吗? 

binlog是逻辑日志。其中一种形式是记录的原始sql语句,另一种形式是记录row上的数据,比如update t set c = c +1 where id = 1; binlog是数据库server层的。和数据是隔离开来的,他可以用来主从复制,和备份恢复数据库用,他不能做到crash safe,

binlog没有能力恢复“数据页”

假设数据先存入,再记录binlog,存入后mysql崩溃,此时数据库中有数据,而binlog中没有,反之,先记录binlog再提交事务,记录binlog后mysql崩溃,此时binlog比数据库中多出一条数据


5. binlog和redolog的不同点有哪些? 

binlog属于数据引擎的上层server层,redolog是属于数据引擎层

redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。

redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。


7. 执行器和innoDB在执行update语句时候的流程是什么样的?

执行器先去找数据引擎要需要更新的行,引擎查找该行,如果改行数据页在内存中则直接返回给执行器,如果不在则从硬盘中读到内存,然后再返回

执行器拿到引擎给的行数据,将数据修改,得到这行新数据,再调用引擎接口写入这行的新数据

引擎将这行更新到内存中,此时sql相当于执行成功会生成redo和undo的内存日志

此时redo log处于准备阶段 会被刷入磁盘持久化,然后告诉执行器执行完成,随时可以提交事务

执行器记录binlog,并记录该日志到磁盘(这里就确定了事务肯定会提交,不然就会执行回滚操作,而不是记录binlog日志)

执行器调用引擎的提交事务接口完成事务提交,把刚刚写入的redolog改为提交状态,同时事务结束了,删除undo日志(当然删除前会看有没有其他事务需要用到该undo日志),更新完成

这一篇写的不错讲解undo日志


8. 如果数据库误操作, 如何执行数据恢复?

binlog会记录所有的逻辑操作,并且是采用“追加写”的形式

同时系统会定期做整库备份。这里的“定期”取决于系统的重要性,可以是一天一备,也可以是一周一备

首先,找到最近的一次全量备份

然后,从备份的时间点开始,将备份的binlog依次取出来,重放到误删表之前的那个时刻。


9. 什么是两阶段提交, 为什么需要两阶段提交, 两阶段提交怎么保证数据库中两份日志间的逻辑一致性?

为了保证redo log 和 bin log的一致性

如果时刻A的地方,也就是写入redo log 处于prepare阶段之后、写binlog之前,发生了崩溃(crash),由于此时binlog还没写,redo log也还没提交,所以崩溃恢复的时候,这个事务会回滚。这时候,binlog还没写,所以也不会传到备库\

如果在时刻B,也就是binlog写完,redo log还没commit前发生crash

如果redo log里面的事务是完整的,也就是已经有了commit标识,则直接提交;

如果redo log里面的事务只有完整的prepare,则判断对应的事务binlog是否存在并完整:
a. 如果是,则提交事务;
b. 否则,回滚事务。

MySQL怎么知道binlog是完整的?

  • statement格式的binlog,最后会有COMMIT;
  • row格式的binlog,最后会有一个XID event。

redo log 和 binlog是怎么关联起来的

它们有一个共同的数据字段,叫XID。崩溃恢复的时候,会按顺序扫描redo log:

  • 如果碰到既有prepare、又有commit的redo log,就直接提交;
  • 如果碰到只有parepare、而没有commit的redo log,就拿着XID去binlog找对应的事务。

 

第三章  事务隔离性

1、事务的特性:原子性、一致性、隔离性、持久性
2、多事务同时执行的时候,可能会出现的问题:脏读、不可重复读、幻读
3、事务隔离级别:读未提交、读提交、可重复读、串行化
4、不同事务隔离级别的区别:
读未提交:一个事务还未提交,它所做的变更就可以被别的事务看到
读提交:一个事务提交之后,它所做的变更才可以被别的事务看到
可重复读:一个事务执行过程中看到的数据是一致的。未提交的更改对其他事务是不可见的
串行化:对应一个记录会加读写锁,出现冲突的时候,后访问的事务必须等前一个事务执行完成才能继续执行
5、配置方法:启动参数transaction-isolation
6、事务隔离的实现:每条记录在更新的时候都会同时记录一条回滚操作。同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)。
7、回滚日志什么时候删除?系统会判断当没有事务需要用到这些回滚日志的时候,回滚日志会被删除。
8、什么时候不需要了?当系统里么有比这个回滚日志更早的read-view的时候。
9、为什么尽量不要使用长事务。长事务意味着系统里面会存在很老的事务视图,在这个事务提交之前,回滚记录都要保留,这会导致大量占用存储空间。除此之外,长事务还占用锁资源,可能会拖垮库。
10、事务启动方式:一、显式启动事务语句,begin或者start transaction,提交commit,回滚rollback;二、set autocommit=0,该命令会把这个线程的自动提交关掉。这样只要执行一个select语句,事务就启动,并不会自动提交,直到主动执行commit或rollback或断开连接。
11、建议使用方法一,如果考虑多一次交互问题,可以使用commit work and chain语法。在autocommit=1的情况下用begin显式启动事务,如果执行commit则提交事务。如果执行commit work and chain则提交事务并自动启动下一个事务。

 

第四章 索引常见数据结构

.1.索引的作用:提高数据查询效率
2.常见索引模型:哈希表、有序数组、搜索树
3.哈希表:键 - 值(key - value)。
4.哈希思路:把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置
5.哈希冲突的处理办法:链表
6.哈希表适用场景:只有等值查询的场景
7.有序数组:按顺序存储。查询用二分法就可以快速查询,时间复杂度是:O(log(N))
8.有序数组查询效率高,更新效率低
9.有序数组的适用场景:静态存储引擎。
10.二叉搜索树:每个节点的左儿子小于父节点,父节点又小于右儿子
11.二叉搜索树:查询时间复杂度O(log(N)),更新时间复杂度O(log(N))
12.数据库存储大多不适用二叉树,因为树高过高,会适用N叉树
13.InnoDB中的索引模型:B+Tree
14.索引类型:主键索引、非主键索引
主键索引的叶子节点存的是整行的数据(聚簇索引),非主键索引的叶子节点内容是主键的值(二级索引)
15.主键索引和普通索引的区别:主键索引只要搜索ID这个B+Tree即可拿到数据。普通索引先搜索索引拿到主键值,再到主键索引树搜索一次(回表)
16.一个数据页满了,按照B+Tree算法,新增加一个数据页,叫做页分裂,会导致性能下降。空间利用率降低大概50%。当相邻的两个数据页利用率很低的时候会做数据页合并,合并的过程是分裂过程的逆过程。
17.从性能和存储空间方面考量,自增主键往往是更合理的选择。

 

第五章  回表 覆盖索引

回表:回到主键索引树搜索的过程,称为回表

左图是主键索引,右图是非主键索引,主键索引叶子节点上是数据行,非主键索引叶子节点上是改行数据的主键.

比如要通过K字段作为条件,查询一个非主键列,则需要先查询到主键,在用主键回表到主键索引上查询到整行数据

 

覆盖索引:某索引已经覆盖了查询需求,称为覆盖索引,例如:select ID from T where k between 3 and 5
这里因为主键ID在k索引上,所以覆盖了查询需求,所以不需要回表.

如果不光查询ID,还需要查询另一个字段u 可以考虑把 k u作为联合索引,这样他们也会变成覆盖索引,避免回表查询


最左前缀原则:B+Tree这种索引结构,可以利用索引的"最左前缀"来定位记录
只要满足最左前缀,就可以利用索引来加速检索。
最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符
第一原则是:如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。
索引下推:在MySQL5.6之前,只能从根据最左前缀查询到ID开始一个个回表。到主键索引上找出数据行,再对比字段值。
MySQL5.6引入的索引下推优化,可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

 

第六章  全局锁,表级锁(表锁,mdl锁)

1.Mysql中的锁分类

全局锁,表级锁,行级锁

2.什么是全局锁,全局读锁怎么加,使用场景是什么?会出现什么问题

全局锁就是对整个数据库实例加锁

全局读锁就是让整个数据库处于只读状态,其他的增删改及数据库结构修改语句都会被阻塞

语句是:Flush tables with read lock

全局锁的使用场景就是 给整个数据库做逻辑备份,也就是把整个库里每个表都select出来存成文档.如果在主库上备份会使业务停摆,在整个备份期间,增删改不可用.如果在从库备份,,备份期间从库不能接收来自主库的binlog会导致主从延迟.

3.官方自带的逻辑备份工具是什么,如何不使用全局锁做逻辑备份

官方使用的是mysqldump,他和全局锁不一样,mysqldump使用参数-single-transaction的时候,导数据之前会启动一个事务,来确保拿到一致性视图,(使用mvcc,和隔离级别可重复读一样),在此期间数据是可以更新的.

之所以还是要有全局锁是因为mysqldump需要事务的支持,如果数据库中存在myISAM这种不支持事务的表时 则不可用

4.什么是表级锁

mysql中表级锁有两种,一种是表锁,一种是元数据锁(mete data lock,MDL)

表锁的语句是  lock tables 表名 read/write 表锁即会限制别的线程的读写,也会限制本线程的读写对象

例如 线程A 执行 lock tables t1 read ,t2 write,线程B 其他线程写t1,读写t2都会阻塞,同时线程A也只能读t1,读写t2,同时也不能访问其他表

主要用来处理并发

元数据锁(MDL):MDL并不需要显示使用,在访问一个表的时候会自动加上,当对一个表进行增删改查时,会加MDL读锁,当对一个表做结构变更时会加写锁

读锁不互斥,所以多个线程可以对一个表做增删改查

读锁和血锁互斥,写锁之间互斥,所以修改数据时,如果两个线程同时修改一个表的结构,其中一个会阻塞(写锁互斥),而如果一个线程在读一张表的时候,另一个线程修改该表结构的操作会被阻塞(读锁,写锁互斥)

5.MDL锁导致的问题

上图中线程A开启事务以后获取读锁,提交事务才会释放读锁,在此期间线程C添加表字段,阻塞,后续线程继续查询数据获取读锁,也会阻塞,假设该表读写频繁,且有重试机制,这个库的线程很快就会爆满

6.如果你要变更的表是一个热点表,虽然数据量不大,但是上面的请求很频繁,而你不得不加个字段,你该怎么做

alter table语句里设置等待时间,拿到mdl写锁就修改,不能拿到就放弃,避免阻塞后续语句,然后再重复这个指令.

 

第七章 行级锁,两阶段锁协议,死锁,死锁检测

1.什么是行锁
行锁就是针对数据行加锁,比如事务A修改了一行数据,同时事务B也要修改同一行,在事务A提交之前,事务B将阻塞.

2.什么是两阶段锁协议,有什么用

在InnoDB事务中,行锁是在需要是才添加的,但并不是不需要了就立刻释放,而是等到事务结束后才释放,这就是两阶段锁协议.

如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

比如线程A要修改行1,新增数据,线程B要修改行1,此时,线程A应该先新增数据,在修改行1,这样就减少了冲突的时间.

3.死锁

当系统不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁

4.怎么处理死锁

一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置。

在InnoDB中,innodb_lock_wait_timeout的默认值是50s,意味着如果采用第一个策略,当出现死锁以后,第一个被锁住的线程要过50s才会超时退出,然后其他线程才有可能继续执行,但是,我们又不可能直接把这个时间设置成一个很小的值,比如1s。这样当出现死锁的时候,确实很快就可以解开,但如果不是死锁,而是简单的锁等待呢?所以,超时时间设置太短的话,会出现很多误伤。

所以我们一般采用第二种

另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑。

主动死锁检测,innodb_deadlock_detect的默认值本身就是on。主动死锁检测在发生死锁的时候,是能够快速发现并进行处理的,但是它也是有额外负担的。

每当一个事务被锁的时候,就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,也就是死锁。

每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度是O(n)的操作。假设有1000个并发线程要同时更新同一行,那么死锁检测操作就是100万这个量级的。虽然最终检测的结果是没有死锁,但是这期间要消耗大量的CPU资源。因此,你就会看到CPU利用率很高,但是每秒却执行不了几个事务。

一个思路是控制并发度。根据上面的分析,你会发现如果并发能够控制住,比如同一行同时最多只有10个线程在更新,那么死锁检测的成本很低,就不会出现这个问题,这个并发控制要做在数据库服务端。如果你有中间件,可以考虑在中间件实现

 

什么是共享锁和排他锁

共享锁又叫做读锁,所有的事务只能对其进行读操作不能写操作,加上共享锁后在事务结束之前其他事务只能再加共享锁,除此之外其他任何类型的锁都不能再加了。

用法:SELECT `id` FROM  table WHERE id in(1,2) LOCK IN SHARE MODE 结果集的数据都会加共享锁

排他锁:若某个事物对某一行加上了排他锁,只能这个事务对其进行读写,在此事务结束之前,其他事务不能对其进行加任何锁,其他进程可以读取,不能进行写操作,需等待其释放。

用法:SELECT `id` FROM mk_user WHERE id=1 FOR UPDATE

注意:由于在innodb中行锁,他是针对索引去锁定该条数据,而不是直接锁定该条数据的。

 

第八章 MVCC undolog 一致性视图 快照读,当前读

1.innodb支持RC和RR隔离级别实现是用的一致性视图(consistent read view)

2.事务在启动时会拍一个快照,这个快照是基于整个库的.
基于整个库的意思就是说一个事务内,整个库的修改对于该事务都是不可见的(对于快照读的情况)
如果在事务内select t表,另外的事务执行了DDL t表,根据发生时间,要嘛锁住要嘛报错(参考第六章)

 

3.什么是undo_log

每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。这个回滚记录就是回滚日志undo_log

如图三个虚线箭头,就是undo log 分别是u1 u2 u3 通过回滚日志可以找到这行记录的历史版本,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。


4.事务是如何实现的MVCC呢?
(1)每个事务都有一个事务ID,叫做transaction id(严格递增)

 (2)InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”的所有事务ID。“活跃”指的就是,启动了但还没提交。数组里面事务ID的最小值记为低水位,当前系统里面已经创建过的事务ID的最大值加1记为高水位。(这里我理解成当前这个事务的ID就是高水位,因为他现在创建事务,分配给他的事务ID就是在之前的事务ID上递增1)

这个视图数组和高水位,就组成了当前事务的致性视图(read-view)

而数据版本的可见性规则,就是基于数据的row trx_id和这个一致性视图的对比结果得到的。

这样,对于当前事务的启动瞬间来说,一个数据版本的row trx_id,有以下几种可能:

如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;

如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;

如果落在黄色部分,那就包括两种情况
a. 若 row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;
b. 若 row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。

 

一个数据版本,对于一个事务视图来说,除了自己的更新总是可见以外,有三种情况:

  • 版本未提交,不可见;
  • 版本已提交,但是是在视图创建后提交的,不可见;
  • 版本已提交,而且是在视图创建前提交的,可见。

这里的数据版本如下图的当前版本 版本1 版本2,事务视图指的是当前这个事务的视图数组如下的[99 ,100]

  • (1,3)还没提交,属于情况1,不可见;
  • (1,2)虽然提交了,但是是在视图数组创建之后提交的,属于情况2,不可见;
  • (1,1)是在视图数组创建之前提交的,可见。

更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)

除了update语句外,select语句如果加锁,也是当前读。

 

5.读提交的逻辑和可重复读的逻辑类似,它们最主要的区别是是什么

  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;
  • 在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。

 

第九章 普通索引 唯一索引选择 change buffer

1.选择普通索引还是唯一索引?
对于查询过程来说
a、普通索引,查到满足条件的第一个记录后,继续查找下一个记录,知道第一个不满足条件的记录
b、唯一索引,由于索引唯一性,查到第一个满足条件的记录后,停止检索
但是,两者的性能差距微乎其微。因为InnoDB根据数据页来读写的。也就是说基本上多出来的查询只是在内存上找速度快


对于更新过程来说:
概念:

change buffer
当需要更新一个数据页,如果数据页在内存中(buffer pool)就直接更新,如果不在内存中,在不影响数据一致性的前提下,InnoDB会将这些更新操作缓存在change buffer中。下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change buffer中的与这个页有关的操作。
change buffer是可以持久化的数据。在内存中有拷贝,也会被写入到磁盘上

merge:将change buffer中的操作应用到原数据页上,得到最新结果的过程,成为merge
访问这个数据页会触发merge,系统有后台线程定期merge,在数据库正常关闭的过程中,也会执行merge

唯一索引的更新不能使用change buffer,因为先要唯一性校验,这个过程得把数据页取到内存,这个时候直接跟新内存就好,没必要change buffer

change buffer用的是buffer pool里的内存,change buffer的大小,可以通过参数innodb_change_buffer_max_size来动态设置。这个参数设置为50的时候,表示change buffer的大小最多只能占用buffer pool的50%。

将数据从磁盘读入内存涉及随机IO的访问,是数据库里面成本最高的操作之一。 
change buffer 因为减少了随机磁盘访问,所以对更新性能的提升很明显。

change buffer使用场景
在一个数据页做merge之前,change buffer记录的变更越多,收益就越大。
对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时change buffer的使用效果最好。这种业务模型常见的就是账单类、日志类的系统。

反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在change buffer,但之后由于马上要访问这个数据页,会立即触发purge过程。
这样随机访问IO的次数不会减少,反而增加了change buffer的维护代价。所以,对于这种业务模式来说,change buffer反而起到了副作用。

索引的选择和实践:尽可能使用普通索引。

redo log 和change buffer的区别:
redo log主要节省的是随机写磁盘的IO消耗(转成顺序写,相当于本来要查询到该数据的数据页,但是现在不用了,直接顺序追加记录在redolog日志里面),而change buffer主要节省的则是随机读磁盘的IO消耗(原本要更新的时候是要先找到数据页,现在不读数据页了,直接记录在changebuffer中)。

流程如下

1.Page 1在内存中,直接更新内存;

2.Page 2没有在内存中,就在内存的change buffer区域,记录下“我要往Page 2插入一行”这个信息

3.将上述两个动作记入redo log中(图中3和4)。

 

第十章.MySQL为什么有时候会选错索引

现象:优化器存在选错索引的可能性

主要的原因是,优化器对不同索引执行代价的判断出现了问题,

比如我们平时在大量删除数据后,索引其实是没有删除掉的 ,会导致优化器在选择索引的时候错误的判断了使用不同索引需要的行数

对于由于索引统计信息不准确导致的问题,你可以用analyze table来解决。

 

再比如说 在排序语句中, 如果有两个索引,A索引会扫描1000行,B索引会扫描5000行,但是B是需要排序的字段这个时候,优化器会选择B索引,虽然行数增加了,但是由于B索引本身是有序的,此时优化器认为可以节省排序的时间,依然会使用B索引

而这些优化器误判的情况,你可以在应用端用force index来强行指定索引,也可以通过修改语句来引导优化器,还可以通过增加或者删除索引来绕过这个问题。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章