• Mysql高级——索引优化和查询优化(3)


    9. 如何给字符串添加索引

    9.1 前缀索引

    MySQL是支持前缀索引的。默认地,如果你创建索引的语句不指定前缀长度,那么索引就会包含整个字符串。

    mysql> alter table teacher add index index1(email);
    #或
    mysql> alter table teacher add index index2(email(6));
    
    • 1
    • 2
    • 3

    如果使用的是index1(即email整个字符串的索引结构),执行顺序是这样的:

    1. 从index1索引树找到满足索引值是’ zhangssxyz@xxx.com ’的这条记录,取得ID2的值;
    2. 到主键上查到主键值是ID2的行,判断email的值是正确的,将这行记录加入结果集;
    3. 取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足email=’ zhangssxyz@xxx.com ’的条件了,循环结束。

    这个过程中,只需要回主键索引取一次数据,所以系统认为只扫描了一行。

    如果使用的是index2(即email(6)索引结构),执行顺序是这样的:

    1. 从index2索引树找到满足索引值是’zhangs’的记录,找到的第一个是ID1;
    2. 到主键上查到主键值是ID1的行,判断出email的值不是’ zhangssxyz@xxx.com ’,这行记录丢弃;
    3. 取index2上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出ID2,再到ID索引上取整行然后判断,这次值对了,将这行记录加入结果集;
    4. 重复上一步,直到在idxe2上取到的值不是’zhangs’时,循环结束。

    也就是说使用前缀索引,定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本。前面已经讲过区分度,区分度越高越好。因为区分度越高,意味着重复的键值越少。

    9.2 前缀索引对覆盖索引的影响

    结论:
    使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是你在选择是否使用前缀索引时需要考虑的一个因素。

    10. 索引下推

    Index Condition Pushdown(ICP)是MySQL 5.6中新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式。ICP可以减少存储引擎访问基表的次数以及MySQL服务器访问存储引擎的次数。

    10.1 使用前后的扫描过程

    在不使用ICP索引扫描的过程:

    storage层:只将满足index key条件的索引记录对应的整行记录取出,返回给server层

    server 层:对返回的数据,使用后面的where条件过滤,直至返回最后一行。

    使用ICP扫描的过程:

    • storage层:

    首先将index key条件满足的索引记录区间确定,然后在索引上使用index filter进行过滤。将满足的indexfilter条件的索引记录才去回表取出整行记录返回server层。不满足index filter条件的索引记录丢弃,不回表、也不会返回server层。

    • server 层:

    对返回的数据,使用table filter条件做最后的过滤。

    使用前后的成本差别
    使用前,存储层多返回了需要被index filter过滤掉的整行记录
    使用ICP后,直接就去掉了不满足index filter条件的记录,省去了他们回表和传递到server层的成本。
    ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例。

    10.2 ICP的使用条件

    ICP的使用条件:
    ① 只能用于二级索引(secondary index)

    ②explain显示的执行计划中type值(join 类型)为range 、 ref 、 eq_ref 或者ref_or_null 。

    ③ 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where过滤。

    ④ ICP可以用于MyISAM和InnnoDB存储引擎

    ⑤ MySQL 5.6版本的不支持分区表的ICP功能,5.7版本的开始支持。

    ⑥ 当SQL使用覆盖索引时,不支持ICP优化方法。

    11. 普通索引 vs 唯一索引

    从性能的角度考虑,你选择唯一索引还是普通索引呢?选择的依据是什么呢?

    假设,我们有一个主键列为ID的表,表中有字段k,并且在k上有索引,假设字段 k 上的值都不重复。这个表的建表语句是:

    mysql> create table test(
        id int primary key,
        k int not null,
        name varchar(16),
        index (k)
    )engine=InnoDB;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    表中R1~R5的(ID,k)值分别为(100,1)、(200,2)、(300,3)、(500,5)和(600,6)。

    11.1 查询过程

    假设,执行查询的语句是 select id from test where k=5

    • 对于普通索引来说,查找到满足条件的第一个记录(5,500)后,需要查找下一个记录,直到碰到第一个不满足k=5条件的记录。
    • 对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。
    • 那么,这个不同带来的性能差距会有多少呢?答案是, 微乎其微。

    11.2 更新过程

    为了说明普通索引和唯一索引对更新语句性能的影响这个问题,介绍一下change buffer。

    当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,
    在不影响数据一致性的前提下, InooDB会将这些更新操作缓存在change buffer中,这样就不需要从磁
    盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change
    buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。
    将change buffer中的操作应用到原数据页,得到最新结果的过程称为merge 。除了访问这个数据页会触
    发merge外,系统有后台线程会定期merge。在数据库正常关闭(shutdown) 的过程中,也会执行merge
    操作。

    如果能够将更新操作先记录在change buffer, 减少读磁盘,语句的执行速度会得到明显的提升。而且,
    数据读入内存是需要占用 buffer pool 的,所以这种方式还能够避免占用内存,提高内存利用率。
    唯一索引的更新就不能使用change buffer ,实际上也只有普通索引可以使用。

    12. 其它查询优化策略

    12.1 EXISTS 和 IN 的区分

    不太理解哪种情况下应该使用 EXISTS,哪种情况应该用 IN。选择的标准是看能否使用表的索引吗?

    12.2 COUNT(*)与COUNT(具体字段)效率

    问:在 MySQL 中统计数据表的行数,可以使用三种方式: SELECT COUNT(*) 、SELECT COUNT(1) 和
    SELECT COUNT(具体字段) ,使用这三者之间的查询效率是怎样的?

    12.3 关于SELECT(*)

    在表查询中,建议明确字段,不要使用 * 作为查询的字段列表,推荐使用SELECT <字段列表> 查询。原因:
    ① MySQL 在解析的过程中,会通过查询数据字典将"*"按序转换成所有列名,这会大大的耗费资源和时
    间。
    ② 无法使用覆盖索引

    12.4 LIMIT 1 对优化的影响

    针对的是会扫描全表的 SQL 语句,如果你可以确定结果集只有一条,那么加上LIMIT 1 的时候,当找到一条结果的时候就不会继续扫描了,这样会加快查询速度。

    如果数据表已经对字段建立了唯一索引,那么可以通过索引进行查询,不会全表扫描的话,就不需要加
    上LIMIT 1 了。

    12.5 多使用COMMIT

    只要有可能,在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT 所释放
    的资源而减少

    COMMIT 所释放的资源:

    • 回滚段上用于恢复数据的信息
    • 被程序语句获得的锁
    • redo / undo log buffer 中的空间
    • 管理上述 3 种资源中的内部花费
  • 相关阅读:
    【QT开发笔记-基础篇】| 第四章 事件QEvent | 4.6 定时器事件
    np中的normalize/histogram/cumsum/interp函数
    浏览器控制台报错Failed to load module script:解决方法
    word 替换全部字母和数字为新罗马
    quickapp_快应用_tabBar
    游戏软件开发与应用软件开发有什么不同呢?
    Go网络请求中配置代理
    matlab绘制尖角colorbar
    Java冒泡排序
    苹果安卓网页的H5封装成App的应用和原生开发的应用有什么不一样?
  • 原文地址:https://blog.csdn.net/qq_51495235/article/details/133149779