书籍 -- 《高性能MySQL》持续更新中(三)

第五章 创建高性能的索引 此处的知识点需要借助《数据结构与算法》这更有助于理解
  1. 索引基础
  • 索引可以包含一个或多个列的值。如果索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效地使用索引的最左前缀列。创建一个包含两个列的索引,和创建两个只包含一列的索引是大不相同的。
  • B-Tree索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据,取而代之的是从索引的根节点开始进行搜索。根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找。通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中值的上限和下限。最终存储引擎要么是找到对应的值,要么该记录不存在。
  • 索引对多个值进行排序的依据是create table语句中定义索引时列的顺序。
  • B-Tree索引的限制
create table people (
    last_name varchar(50) not null,
    first_name varchar(50) not null,
    dob date not null,
    gender enum('m','f') not null,
    key (last_name,first_name,dob)
);
  • B-tree 索引的限制

    • 如果不是按照索引的最左列开始查找,则无法使用索引。例如上面例子中的索引无法用于查找bill的人,也无法查找某个特定生日的人,因为这两列不都是最左数据列。类似地,也无法查找姓氏以某个字母结尾的人。
    • 不能跳过索引中的列,也就是说,前面所述的索引无法用于查找姓为Smith并且在某个特定日期出生的人。如果不指定名(first_name),则MySQL只能使用索引的第一列。
    • 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化 查找。例如:有查询where last_name='Smith' and first_name like 'J%' and dob = '1976-12-23'这个查询只能使用索引的前两列,因为这里like是一个范围条件(但是服务器可以把其余列用于其他目的)。如果范围查询列值的数量有限,那么可以通过使用多个等于条件来替代范围条件。
第六章 查询性能优化
  1. 为什么查询速度会慢
  • 查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端。其中“执行”可以认为是整个生命周期中最重要的阶段,这其中包括了大量为了检索数据到存储引擎的调用后的数据处理,包括排序,分组等。
  1. 慢查询基础:优化数据访问
  • 大部分性能低下的查询都可以通过减少访问的数据量的方式进行优化。

    • 确认应用程序是否在检索大量超过需要的数据。这通常意味着访问了太多的行,但有时候也可能是访问了太多的列。
    • 确认MySQL服务器是否在分析大量超过需要的数据行。

2.1 是否向数据库请求了不需要的数据

  • 查询不需要的记录

    • 一个常见的错误是常常会误以为MySQL会只返回需要的数据,实际上MySQL却是先返回全部结果集在进行计算。最简单有效的方法就是在这样的查询后面加上LIMIT
  • 多表关联时返回全部列

    • 如果是多表查询,一定要只查询出需要筛选的列,不要*。
  • 总是取出全部列

    • 每次看到select * 的时候都需要用怀疑的眼光审视,取出全部列会让优化器无法完成索引覆盖扫描这类优化,还会为服务器带来额外的I/O、内存和CPU的消耗。当然,查询返回超过需要的数据也不总是坏事,有的时候可以提高相同代码片段的复用性。获取并缓存所有的列的查询,相比多个独立的只获取部分列的查询可能就更有好处。
  • 重复查询相同的数据

    • 不断地重复执行相同的查询,然后每次都返回完全相同的数据。例如,在用户评论的地方需要查询用户头像的URL,那么用户多次评论的时候,可能就会反复查询这个数据,比较好的方案是,当初次查询的时候将这个数据缓存起来,需要的时候从缓存中取出,这样性能显然会更好。

2.2 MySQL是否在扫描额外的记录

  • 接下来应该看下查询返回结果是否扫描了过多的数据,对于MySQL的衡量查询开销的三个指标:

    • 响应时间(服务时间和排队时间之和)
    • 扫描的行数
    • 返回的行数
  • 检查慢日志记录是找出扫描行数过多的查询的好办法。

  • 如果查询没有办法找到合适的访问类型,那么解决的最好办法通常就是增加一个合适的索引。

  • 在explain语句中的type列反应了访问类型。访问类型有很多种,从全表扫描到索引扫描、范围扫描、唯一索引查询、常数引用等。这里列的这些,速度是从慢到快,扫描的行数也是从小到大。

  • 一般MySQL能够使用如下三种方式应用where条件,从好到坏依次为:

    • 在索引中使用where条件来过滤不匹配的记录。这是在存储引擎层完成的。
    • 使用索引覆盖扫描(在extra列中出现了using index)来返回记录,直接从索引中过滤不需要的记录并返回命中的结果。这是在MySQL服务器层完成的,但无须再回表查询记录。
    • 从数据表中返回数据,然后过滤不满足条件的记录(在extra列中出现using where)。这在MySQL服务器层完成,MySQL需要先从数据表读出记录然后过滤。
  • 如果发现查询需要扫描大量的数据但只返回少数的行,那么通常可以尝试下面的技巧去优化它:

    • 使用索引覆盖扫描,把所有需要用的列都放在索引中,这样存储引擎无须回表获取对应行就可以返回结果了。
    • 改变库表结构。例如使用单独的汇总表。
    • 重写这个复杂的查询,让MySQL优化器能够以更优化的方式执行这个查询。

Guess you like

Origin blog.csdn.net/qq_38721452/article/details/112275243