深入理解MySQL面试必备索引设计和优化原则

深入理解MySQL面试必备索引设计和优化原则

  • 一、什么是索引
  • 二、基础
  • 三、B-Tree
  • 四、mysql树的结构
  • 五、B-tree 索引的优点和为什么使用
  • 六、索引的限制
  • 七、什么情况不是使用索引
  • 八、全文索引
  • 九、前缀索引
  • 十、 聚簇索引
  • 十一、MyISAM使用的是非聚簇索引
  • 十二、覆盖索引
  • 十三、延迟索引
  • 十四、使用索引扫描来做排序
  • 十五、联合索引
  • 十六、优化排序
  • 十七、其它
  • 十八、大表数据查询,怎么优化
  • 十九、超大分页怎么处理?
  • 二十、索引的优点
  • 二十一、SQL优化
  • 二十二、基于主键索引和普通索引的查询有什么区别

一、什么是索引

存储引擎用于快速找到记录的一种数据结构

二、基础

其先在索引中找到对应的值,然后根据匹配的索引记录找到对应的数据行

select first_name from sakila where actor_id = 5 

如果在actor_id列上有索引,则mysql 将使用该索引找到actor_id为5的行
就是说,Mysql先在索引上按值进行查找,然后返回所有包含该值的数据行

myIsam 索引通过数据的物理位置引用-- 都指向物理行(磁盘位置).
Innodb 根据主键引用

三、B-Tree

B-Tree 索引能够加快访问数据的速度,因为存储引擎不在需要进行全表扫描来获取需要的数据, 从索引的根节点开始进行搜索
深入理解MySQL面试必备索引设计和优化原则_第1张图片
深入理解MySQL面试必备索引设计和优化原则_第2张图片

每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

  1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】
  2. 比较关键字29在区间(17,35),找到磁盘块1的指针P2。
  3. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】
  4. 比较关键字29在区间(26,30),找到磁盘块3的指针P2。
  5. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】
  6. 在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

最重要的一点就是所有叶子节点都出现在同一层,叶子节点不包含任何关键字的信息

四、mysql树的结构

从上一节中的B-Tree结构图中可以看到每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

深入理解MySQL面试必备索引设计和优化原则_第3张图片

深入理解MySQL面试必备索引设计和优化原则_第4张图片
根节点是存在内存当中
非根节点和页子节点是放到磁盘当中的

B+ 树基于 B 树做出了改进,主流的 DBMS 都支持 B+ 树的索引方式,比如 MySQL。B+ 树和 B 树的差异在于以下几点:

  1. 有 k 个孩子的节点就有 k 个关键字。也就是孩子数量 = 关键字数,而 B 树中,孩子数量 = 关键字数 +1。
  2. 非叶子节点的关键字也会同时存在在子节点中,并且是在子节点中所有关键字的最大(或最小)。
  3. 非叶子节点仅用于索引,不保存数据记录,跟记录有关的信息都放在叶子节点中。而 B 树中,非叶子节点既保存索引,也保存数据记录。
  4. 所有关键字都在叶子节点出现,叶子节点构成一个有序链表,而且叶子节点本身按照关键字的大小从小到大顺序链接。

下图就是一棵 B+ 树,阶数为 3,根节点中的关键字 1、18、35 分别是子节点(1,8,14),(18,24,31)和(35,41,53)中的最小值。每一层父节点的关键字都会出现在下一层的子节点的关键字中,因此在叶子节点中包括了所有的关键字信息,并且每一个叶子节点都有一个指向下一个节点的指针,这样就形成了一个链表。

深入理解MySQL面试必备索引设计和优化原则_第5张图片

比如,我们想要查找关键字 16,B+ 树会自顶向下逐层进行查找:

  1. 与根节点的关键字 (1,18,35) 进行比较,16 在 1 和 18 之间,得到指针 P1(指向磁盘块 2)
  2. 找到磁盘块 2,关键字为(1,8,14),因为 16 大于 14,所以得到指针 P3(指向磁盘块 7)
  3. 找到磁盘块 7,关键字为(14,16,17),然后我们找到了关键字 16,所以可以找到关键字 16 所对应的数据。

整个过程一共进行了 3 次 I/O 操作,看起来 B+ 树和 B 树的查询过程差不多,但是 B+ 树和 B 树有个根本的差异在于,B+ 树的中间节点并不直接存储数据。这样的好处都有什么呢?

首先,B+ 树查询效率更稳定。因为 B+ 树每次只有访问到叶子节点才能找到对应的数据,而在 B 树中,非叶子节点也会存储数据,这样就会造成查询效率不稳定的情况,有时候访问到了非叶子节点就可以找到关键字,而有时需要访问到叶子节点才能找到关键字。

其次,B+ 树的查询效率更高,这是因为通常 B+ 树比 B 树更矮胖(阶数更大,深度更低),查询所需要的磁盘 I/O 也会更少。同样的磁盘页大小,B+ 树可以存储更多的节点关键字

不仅是对单个关键字的查询上,在查询范围上,B+ 树的效率也比 B 树高。这是因为所有关键字都出现在 B+ 树的叶子节点中,并通过有序链表进行了链接。而在 B 树中则需要通过中序遍历才能完成查询范围的查找,效率要低很多

优点一: B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域

优点二: B+树所有的Data域在叶子节点,并且所有叶子节点之间都有一个链指针。 这样遍历叶子节点就能获得全部数据,这样就能进行区间访问啦。在数据库中基于范围的查询是非常频繁的,而B树不支持这样的遍历操作。

B+tree 但它所有关键字的信息都出现在叶子节点上,并且包含这些关键字记录的指针,叶子结点可以按照关键字的大小顺序链接。还有就是它所有的数据保存在叶子节点上

B+tree 索引是双向链表结构,而且用B+tree结构做检索要比B-tree快,可以看出访问关键字的顺序是连续性的,不用再访问上一个结点,而且叶子结点包含所有数据信息

B+Tree相对于B-Tree有几点不同:

  1. 非叶子节点只存储键值信息。
  2. 所有叶子节点之间都有一个链指针。
  3. 数据记录都存放在叶子节点中。

B-tree 平衡多路查找树

对于一个具有m阶的B树,具有如下一些特征:

  1. 根节点至少有两颗子树
  2. 每一个非根的分支节点都有k-1个元素和k个孩子,每个叶子节点都有k-1个元素 (元素和孩子之间是什么关系,元素树等于孩子树减去1) 其中 m/2 <= k <=m
  3. 所有叶子节点都位于同一层
  4. 每个节点中元素都从小到大排列,其中节点k-1个元素正好是k个孩子的值域划分

深入理解MySQL面试必备索引设计和优化原则_第6张图片
B+tree 双链表

  • 叶子节点通过链表的形式连接起来了
  • 分支节点存储的元素,在我们叶子节点中还是会出现一次,根节点也会在孩子节点出现一次

这里是引用

  1. 有n棵子树的节点中包含n个关键字(有三个元素,就是有三个孩子)
  2. 数据存储在叶子节点上(对于分支节点当做索引来使用),叶子节点按照关键字从小到大顺序链接(1 2 3 5 8 9 11 13 15)这是叶子节点
  3. 所有的分支节点可看做是索引,并且存储了其子树中的最大(或最小)值

深入理解MySQL面试必备索引设计和优化原则_第7张图片
简单描述 B树与B+树的对比

  1. B树中,每个节点纪要存储索引信息,又要存储数据信息,而B+树只在叶子节点进行数据的存储,使得一个节点能够读取到更多的索引信息,提高查询效率,侧面也减少了磁盘IO次数
  2. B+树所有叶子节点在同一层,并以链表的形式进行存储,当我们需要遍历数据的时候,只需要顺讯遍历叶子节点可以了,非常适合范围查找,如果是B-tree查找4到9的数据,需要在树里面寻找

深入理解MySQL面试必备索引设计和优化原则_第8张图片
3. 查询性能稳定

五、B-tree 索引的优点和为什么使用

按照顺序存储数据

  1. 索引大大减少了服务器扫描的数据量
  2. 索引可以帮助服务器避免排序和临时表
  3. 索引可以将随机I/O变为顺序I/O

六、索引的限制

 1. 如果不是按照索引的最左列开始查找.则无法使用索引 --左前缀原理 	
 2. 不能跳过索引中的列,如果第一个没有索引,第二个就用不上
 3. 如果查询中有某个列的范围查找 ,则其右边所有列都无法使用索引优化查找,例如:
 有查询where last_name = 'Smith' and first_name LIKE 'J%' and dob = '1976-12-23',这个查询只能使用索引的前两列,
 因为LIKE是一个范围条件   --优化用上联合索引

七、什么情况不是使用索引

  1. 很少数据的列,性别, 0或者1
  2. 频繁更新的字段不要使用索引,导致索引页频繁变化,降低效率
  3. 查询中很少使用到的列,不创建索引,降低mysql的性能和增大了空间需

八、全文索引

全文索引查找的是文本中的关键词

九、前缀索引

有时候需要索引很长的字符列,这会让索引变得大且慢,对于BLOB、TEXT或者很长的VARCHAR类型的,必须使用前缀索引

计算完整列的选择性:

select count(distinct LEFT(name,3))/count(*) as a1, count(distinct LEFT(name,4))/count(*) as a2 from admin;
select count(distinct name)/count(*) from admin;

pt-query-digest 提取"最差"查询

经验法则考虑的是全局基数和选择性

select count(distinct sftaff_id)/count(*) as staff_id_selectivity,
select count(distinct customer_id)/count(*) as customer_id_selectivity,
count(*)
 from payment\G;
*********************1.row********************
staff_id_selectivity:0.0001
customer_id_selectivity:0.0373
count(*):16049

customer_id的选择性更高,所以答案时将其作为索引列的第一列

ALTER TABLE payment ADD KEY(customer_id,staff_id);

下面的语句查询非常的慢

select count(distinct threadid) as count_value from message
where (groupid =10137) and (userid=1288826) and (anonymous =0)
order by priority desc,modifieddate desc

如果考虑一下 userid 和groupid的条件匹配的行数,可能就会用不同的想法了

select count(*),sum(groupID=10137),sum(userid=128826),sum(anonymous =0 ) from Message \G
****************************1.row****************************
count(*): 4142217
sum(groupID = 10137)4092654
sum(userID=1288826): 1288496
sum(anonymous =0): 4141934

从上面的结果来看符合组(groupid)条件几乎满足表中的所有行、符合用户(userid)条件的130完条记录,也就是说索引基本上没什么用

解决方案就是修改应用程序代码,区分这类特殊用户和组,禁止针对这类用户和组执行这个查询

十、 聚簇索引

创建主键id

聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据

聚簇索引 不是一种单独的索引类型,而是一种数据存储方式。但Innodb的聚簇索引实际上在同一个结构中保存了B+Tree索引和数据行

解释:
索引类型分为主键索引和非主键索引。主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。

非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。

聚簇索引(innobe)的叶子节点就是数据节点(存储的行数据),分裂的时候,还要移动行数据 ,中间的节点页保存指向下一层页面的指针,按照一定顺序一个个紧密地排列在一起存储

 1. InnoDB使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用"where id =14"这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。
 2. 若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。(重点在于通过其他键需要建立辅助索引)

在简单的描述

聚簇索引 按照英文字母查
辅助键索引就是通通记录主见的值,依赖主见的
先查找辅助键索引,找到14id(相当于书签),在去查主见索引,找到需要的数据
好处:节省空间

如果没有见主见
第一个唯一非空的作为主见,它会自己生成,你们是看不见的 ,还是存在占6个字节
深入理解MySQL面试必备索引设计和优化原则_第9张图片
优势:

1.由于行数据和聚簇索引的叶子节点存储在一起,同一页中会有多条行数据,访问同一数据页不同行记录时,已经把页加载到了Buffer中(缓存器),再次访问时,会在内存中完成访问,不必访问磁盘。这样主键和行数据是一起被载入内存的,找到叶子节点就可以立刻将行数据返回了,如果按照主键Id来组织数据,获得数据更快。
简答描述

  1. 电子邮箱,根据用户ID来聚集数据,不使用聚簇索引,每封邮件都可能导致一次磁盘IO
  2. 数据访问快,行数据和叶子节点都在一起
  3. 可以用覆盖索引,直接访问页节点中的主键

2.辅助索引的叶子节点,存储主键值,而不是数据的存放地址(行指针).。这样的策略减少了

  1. 当行数据放生变化时,索引树的节点也需要分裂变化;或者是我们需要查找的数据,在上一次IO读写的缓存中没有,需要发生一次新的IO操作时,可以避免对辅助索引的维护工作,只需要维护聚簇索引树就好了。
  2. 另一个好处是,因为辅助索引存放的是主键值,减少了辅助索引占用的存储空间大小。

缺点:
聚簇数据最大限度提高了I/O ,但如全部数据放在内存中,则访问顺序就没那么重要了聚簇索引就没什么优势了

提醒:
使用InnoDB时应该尽可能底按照顺序插入数据
什么叫页分裂?是指数据在硬盘上存储在多个不同的数据页(叶子页)

  1. 写入的目标页可能已经刷到磁盘上并从缓存中移除,或者是还没有被加载到缓存中、Innnodb在插入之前不得不先找到从磁盘读取目标页到内存中。这将导致大量的随机I/O
  2. 因为写入是乱序的,Innodb不得不频繁地做页分裂操作,以便为新的行分配空间,页分裂会导致移动大量数据,一次插入最少需要修改三个页面不是一个页
  3. 由于频繁的页分裂,页会变得稀疏并被不规则地填充、所以最终数据会有碎片

十一、MyISAM使用的是非聚簇索引

非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

在简单的描述

1、非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针
2、非聚簇索引 按照偏旁去查,按照一横和竖,指不定谁在前谁在后
通过主见或者辅助键索引也好,都可以查找到数据,不会走两遍

坏处:占用空间

深入理解MySQL面试必备索引设计和优化原则_第10张图片

十二、覆盖索引

mysql只需要通过索引就可以返回查询所需要的数据,而不必在查询索引之后再去回表查询数据了,这样就减少了大量的I/O操作,查询速度也相当的快,在执行计划中出现 Extra: Using where: Using index

所建立的索引where 上字段必须在索引中,获取的列也在索引中

id_photo_mobile_name(photo,mobile,name,id)
select `name` from customers c where c.photo = "0" and c.mobile = "0" and city="长沙"

不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引的列,而哈希索引、空间索引和全文索引等都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引

在下面这个表 T 中,如果我执行 select * from T where k between 3 and 5,需要执行几次树的搜索操作,会扫描多少行?

mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0,
s varchar(16) NOT NULL DEFAULT ‘’,
index k(k))
engine=InnoDB;

insert into T values(100,1, ‘aa’),(200,2,‘bb’),(300,3,‘cc’),(500,5,‘ee’),(600,6,‘ff’),(700,7,‘gg’);

深入理解MySQL面试必备索引设计和优化原则_第11张图片

现在,我们一起来看看这条 SQL 查询语句的执行流程:

  1. 在 k 索引树上找到 k=3 的记录,取得 ID = 300;
  2. 再到 ID 索引树查到 ID=300 对应的 R3;
  3. 在 k索引树取下一个值 k=5,取得 ID=500;
  4. 再回到 ID 索引树查到 ID=500 对应的 R4;
  5. 在 k 索引树取下一个值k=6,不满足条件,循环结束。 在这个过程中,

回到主键索引树搜索的过程,我们称为回表。可以看到,这个查询过程读了 k 索引树的 3 条记录(步骤1、3 和 5),回表了两次(步骤 2 和 4)

在这个例子中,由于查询结果所需要的数据只在主键索引上有,所以不得不回表。那么,有没有可能经过索引优化,避免回表过程呢?

优势
由于覆盖索引可以减少树的搜索次数,显著提升查询的性能,极大减少数据的访问量

十三、延迟索引

select * from products where actor='SEAN CARREY' and title like '%APOLLO%\G
  1. 无法索引覆盖,因为查询从表中选择了所有的列,而没有任何索引覆盖了所有的列,不过理论,where条件中的列有索引可以覆盖,只能用该索引找到对应的actor,并检查title是否匹配,过滤之后在读取需要的数据行
  2. 如果是通配符开头的LIKE查询,存储引擎就无法做比较匹配,这种情况Mysql服务器只能提取数据行的值而不是索引值来做比较

解决方式
先将索引扩展之覆盖三个数据列(artist,title,prod_id)

select * from products JOIN(select prod_id from products where artist='SEAN CARREY' add title LIKE '%APOLLO%') as ti on (t1.prod_id=products.prod_id)\G

延迟关联,在查询的第一阶段mysql可以使用索引覆盖,在from子句的子查询中找到匹配prod_id,然后根据这些prod_id值在外层查询匹配获取需要的所有的列值,虽然无法使用索引覆盖整个查询,但总算比完全无法利用索引覆盖的好

十四、使用索引扫描来做排序

扫描索引本身是很快,因为只需要从一条索引记录移到紧接着的下一条记录,但如果索引不能覆盖查询所需的全部列,那就不得不每扫描一条索引记录就都回表查询一次对应的行,这基本上都是随机I/O,因此按索引顺序读取数据的速度通常要比顺序的全表扫描慢,尤其实在I/O密集型的工作负载时,

如果查询关联多张表,则只有当ORDER by 子句引用的字段全部为第一个表时,才能使用索引做排序

PRIMARY KEY (rental_id),
UNIQUE KEY rental_date(rental_date,inventory_id,customer_id)
KEY idx_fx_inventory_id (inventory_id),
KEY idx_fx_customer_id (customer_id),
KEY idx_fx_staff_id (staff_id),

#即时ORDER BY 子句不满足索引的最左前缀的要求,也可以用于查询排序,这是因为索引的第一列被指定为一个常数

select rental_id,staff_id from sakila.rental where rental_date = '2005-05-25' order by inventory_id,customer_id \G

这个使用索引最左前缀

where rental_data = ‘2005-05-25’ order by inventory_id desc;
where rental_data > ‘2005-05-25’ order by rental_date,inventory_id

不能使用索引做排序

  1. 两种不同排序方向,但是索引列都是正序排序的
where rental_date = '2005-05-25' order by inventory_id  desc,customer_id asc;
  1. order by 子句用了一个不在索引中的列
where rental_date = '2005-05-25' order by inventory_id ,staff_id;
  1. 无法组合成索引的最左前缀
where rental_date = '2005-05-25' order by customer_id asc;
  1. 查询索引列的第一个列上市范围条件,所有无法使用索引的其余的
where rental_date > '2005-05-25' order by inventory_id,customer_id;
  1. 查询在inventory_id列上有多个等于条件,对于排序来说,这也是一种范围查询
where rental_date ='2005-05-25' and inventory_id in (1,2)  order by customer_id
  1. 理论可以索引进行关联排序的,但是优化器在优化时将file_actor
    表当做关联的第二张表,实际上不能使用索引 (file 关联 file_actor)
select actor_id,title from sakila.file_actor inner join sakila.film USING(film_id) order by actor_id \G

十五、联合索引

实在表中两个或两个以上的列上创建的索引,利用索引中的附加列,可以缩小检索的范围,更快地搜索到数据

create index idx_c1_c2 on t (c1,c2);

使用到索引

select * from  t where c1=某值

select * from t where c2=某值 and c1=某值

select * from t where c1=某值 and c2 = 某值 in(某值,某值);

select * from order by c1,c2;

select * from t where c1=某值 order by c2;

使用不到索引

select * from t where c2=某值

select * from t where c2=某值 order by c1;

select * from t where c1=某只 or c2 = 某值

十六、优化排序

因为偏移量的增加,MYSQL需要花费大量的时间来扫描要丢弃的数据

select <cols> from profiles where sex='M' order by rating LIMit 1000000,10

优化这类比较好的策略是延迟关联,通过使用覆盖索引查询返回需要的主键,在根据这些主见关联原表获得需要的行,这可以减少mysql扫描那些需要丢弃的行数,高效使用(sex,rating) 索引进行排序和分页

using等价于join操作中的on,例如a和b根据id字段关联,那么以下等价
using(id)
on a.id=b.id

select <cols> from profiles inner join( select <primary key cols> from profiles where x.sex='M' order by rating Limit 1000000,10) AS x USING(<primary key cols>);

十七、其它

后通配 走索引 前通配 走全表。(’%明%’)

主键 是一种特殊的唯一索引,不允许有空值。 可以被其他表引用为外键

唯一 索引列的值必须唯一,但允许有空值 不能被引入外键

普通 最基本的索引,没有任何限制

联合 如果这个字段在联合索引中所有字段的第一个,就会使用到索引,否者就不能使用

索引 左前缀

数据结构文件.frm和数据文件.idb 其中.idb中存放的是数据和索引信息 是存放在一起的

十八、大表数据查询,怎么优化

优化shema、sql语句+索引;
第二加缓存,memcached, redis;
主从复制,读写分离;
垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;

十九、超大分页怎么处理?

超大的分页一般从两个方向上来解决.

  • 数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select * from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快.同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit10,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.
  • 从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可.

二十、索引的优点

  1. 提高数据检索效率
  2. 提高聚合函数效率
  3. 提高排序效率

二十一、SQL优化

  1. 先看表的数据类型是否设计的合理,有没有遵守选取数据类型越简单越小的原则
  2. 表中的碎片是否整理
  3. 表的统计信息是否收集,只有统计信息准确,执行计划才可以帮助我们优化SQL
  4. 查看执行计划,检查索引的使用情况,没有用到索引,考虑创建
  5. 在创建索引之前,还要查看索引的选择性,来判断这个字段是否合适创建索引
  6. 创建索引之后,在查看一下执行计划,对比这两次的结果,看是否查询效率提高了

二十二、基于主键索引和普通索引的查询有什么区别

深入理解MySQL面试必备索引设计和优化原则_第12张图片

根据上面的索引结构说明,我们来讨论一个问题:基于主键索引和普通索引的查询有什么区别?

如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;

如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。

参考的文章
https://www.jianshu.com/p/54c6d5db4fe6 #高性能MySQL的书
https://blog.csdn.net/u012164509/article/details/92407781
https://blog.csdn.net/hao65103940/article/details/89032538
https://blog.csdn.net/qq_36204764/article/details/99291423
https://blog.csdn.net/qq_21993785/article/details/80580679
https://blog.csdn.net/qq_35923749/article/details/88068659
https://blog.csdn.net/xiedelong/article/details/81417049

你可能感兴趣的:(Mysql)