SQL优化(二)、2.2.2存在索引但不能使用索引的场景

有时有索引但并不一定被优化器选择使用,那么什么时候不使用索引呢?通常的场景大致有:

  • 1、 以%开头的like查询,b-tree索引不起作用
    解决方案:
    ①、先投影主键索引覆盖扫描进行模糊查询,然后内连接,理论上比目前这种直接全表扫描更快。具体可参看后面的样例说明。
    ②、子查询 提供方案不为绝对,具体看实际情况。
  • 2、数据类型出现隐式转换的时候也不会使用索引。比如字符串使用检索条件值没加引号,那该列建立的索引不会生效。
  • 3、复合索引的情况下,加入查询条件不包含索引列最左边部分,即不满足最左原则leftmost,是不会使用复合索引的。
  • 4、MYSQL估计使用索引比全表扫描更慢,则不适用索引了。
  • 5、用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及到的索引都不会被用到

感兴趣可以具体看下面样例,针对每点都有说明

  • 1、 以%开头的like查询,b-tree索引不起作用,一般推荐使用fulltext全文索引来解决类似全文检索问题。或者考虑利用innodb表时聚簇表特点,采取一种轻量级的解决方式:通常但不绝对,索引比表小,扫描索引比扫描表快的多,innodb表上二级索引idx_last_name实际上存储字段last_name还有主键actor_id,理想的访问方式先扫描二级索引idx_last_name获取满足条件last_name like '%NI%'的主键actor_id列表,然后根据主键回表检索记录,这样避免全表扫描导致的大亮io请求。eg:
mysql> explain select * from actor where last_name like '%NI%'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: actor
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 200
        Extra: Using where
1 row in set (0.02 sec)

解决方案1:试试先投影查询然后内连接 ,这种也叫谓词下推

mysql> explain select * from (select actor_id from actor where last_name like '%NI%') a,actor b where a.actor_id=b.actor_id\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 200
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: b
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 2
          ref: a.actor_id
         rows: 1
        Extra: NULL
*************************** 3. row ***************************
           id: 2
  select_type: DERIVED
        table: actor
         type: index
possible_keys: NULL
          key: idx_actor_last_name
      key_len: 137
          ref: NULL
         rows: 200
        Extra: Using where; Using index
3 rows in set (0.00 sec)

可以看出 执行计划是通过内层查询的using index (代表索引覆盖扫描),之后通过主键join操作,去actor表获取最终查询结果,理论上比直接全表扫描更快。

  • 2 数据类型存在隐式转换的不会使用索引。特别是当列类型是字符串,那么作为检索条件时,值一定要用引号引起来。否则即便有索引,mysql也不会引用到,mysql默认把输入的常量值进行转换以后才进行检索。比如actor.last_name,eg:
explain select  * from actor where last_name=1\G 
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: actor
         type: ALL
possible_keys: idx_actor_last_name
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 200
        Extra: Using where
1 row in set (0.09 sec)
加上引号后,可以看到使用了索引。
explain select  * from actor where last_name='1'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: actor
         type: ref
possible_keys: idx_actor_last_name
          key: idx_actor_last_name
      key_len: 137
          ref: const
         rows: 1
        Extra: Using index condition
1 row in set (0.00 sec)
  • 3、复合索引不满足最左原则,不会使用该复合索引
explain select * from payment where amount=3.98 and last_update='2006-02-15 22:12:32'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: payment
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
        Extra: Using where
1 row in set (0.06 sec)

4 评估使用所以比全表扫描更慢,则不使用索引。eg:

mysql> update film_text set title=concat('S',title);
Query OK, 1000 rows affected (0.35 sec)
Rows matched: 1000  Changed: 1000  Warnings: 0

mysql> explain select * from film_text where title like 'S%'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film_text
         type: ALL
possible_keys: idx_title_desc_part,idx_title_description
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1000
        Extra: Using where
1 row in set (0.02 sec)

mysql5.6版本中,可以透过trace清晰看到优化器选择的过程,全表扫描table scan需要访问的记录rows 为1000,代价cost计算为233.53;

“table_scan:{
"rows":1000,
"cost":233.53
}”/*table_scan*/

面对idx_title_desc_part索引过滤条件时,优化器预估需要返回1998条记录,访问代价为1198.6,远高于全表扫描的代价,索引优化器倾向于选择全表扫描。
更换查询的值为一个选择率更高的值,就能发现优化器更倾向于选择索引扫描。

mysql> explain select *from film_text where title like 'SW'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film_text
         type: range
possible_keys: idx_title_desc_part,idx_title_description
          key: idx_title_desc_part
      key_len: 32
          ref: NULL
         rows: 1
        Extra: Using where
1 row in set (0.02 sec)

通过trace能够得知,title like 'SW%'优化器预估需要返回66条记录,代价cost为80.21,远小于全表扫描的代价,所以优化器倾向于选择索引扫描,所以查询的时候,筛选性越高越容易使用到索引,筛选性越低越不容易使用索引。

  • 5 、用or分割开的条件,不区分在or的前后,如果or的一边条件中的列有索引,另一边的列中没有索引,涉及到的索引均不会被用到,eg:
explain select * from payment where customer_id=203 or amount=3.96\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: payment
         type: ALL
possible_keys: idx_fk_customer_id
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
        Extra: Using where
1 row in set (0.00 sec)

在这里插入图片描述

因为or后面的条件列没有索引,所以查询走的全表扫描,在存在全表扫描的情况下,没必要多一次索引扫描增加I/O访问,一次全表扫描过滤条件就足够了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章 全局在胸——用工具对SQL整体优化 1 1.1 都有哪些性能工具 1 1.1.1 不同调优场景分析 2 1.1.2 不同场景对应工具 2 1.2 整体性能工具的要点 4 1.2.1 五大性能报告的获取 5 1.2.2 五大报告关注的要点 10 1.3 案例的分享与交流 18 1.3.1 和并行等待有关的案例 18 1.3.2 和热块竞争有关的案例 19 1.3.3 和日志等待有关的案例 20 1.3.4 新疆某系统的前台优化 20 1.3.5 浙江某系统的调优案例 21 1.4 本章总结延伸与习题 21 1.4.1 总结延伸 21 1.4.2 习题训练 23 第2章 风驰电掣——有效缩短SQL优化过程 24 2.1 SQL调优时间都去哪儿了 25 2.1.1 不善于批处理频频忙交互 25 2.1.2 无法抓住主要矛盾瞎折腾 25 2.1.3 未能明确需求目标白费劲 26 2.1.4 没有分析操作难度乱调优 26 2.2 如何缩短SQL调优时间 27 2.2.1 先获取有助调优的数据库整体信息 27 2.2.2 快速获取SQL运行台前信息 27 2.2.3 快速拿到SQL关联幕后信息 28 2.3 从案例看快速SQL调优 29 2.3.1 获取数据库整体的运行情况 29 2.3.2 获取SQL的各种详细信息 29 2.4 本章总结延伸与习题 32 2.4.1 总结延伸 32 2.4.2 习题训练 33 第3章 循规蹈矩——如何读懂SQL执行计划 34 3.1 执行计划分析概述 35 3.1.1 SQL执行计划是什么 35 3.1.2 统计信息用来做什么 36 3.1.3 数据库统计信息的收集 37 3.1.4 数据库的动态采样 37 3.1.5 获取执行计划的方法(6种武器) 40 3.2 读懂执行计划的关键 48 3.2.1 解释经典执行计划方法 49 3.2.2 总结说明 55 3.3 从案例辨别低效SQL 55 3.3.1 从执行计划读出效率 56 3.3.2 执行计划效率总结 60 3.4 本章习题、总结与延伸 60 第4章 运筹帷幄——左右SQL执行计划妙招 62 4.1 控制执行计划的方法综述 63 4.1.1 控制执行计划的意义 63 4.1.2 控制执行计划的思路 64 4.2 从案例探索其方法及意义 65 4.2.1 HINT的思路 65 4.2.2 非HINT方式的执行计划改变 72 4.2.3 执行计划的固定 100 4.3 本章习题、总结与延伸 102 第5章 且慢,感受体系结构让SQL飞 103 5.1 体系结构知识 104 5.1.1 组成 104 5.1.2 原理 104 5.1.3 体会 105 5.2 体系与SQL优化 106 5.2.1 与共享池相关 107 5.2.2 数据缓冲相关 111 5.2.3 日志归档相关 116 5.3 扩展优化案例 118 5.3.1 与共享池相关 118 5.3.2 数据缓冲相关 122 5.3.3 日志归档相关 126 5.4 本章习题、总结与延伸 130 第6章 且慢,体验逻辑结构让SQL飞 132 6.1 逻辑结构 132 6.2 体系细节与SQL优化 133 6.2.1 Block 133 6.2.2 Segment与extent 137 6.2.3 Tablespace 139 6.2.4 rowid 139 6.3 相关优化案例分析 140 6.3.1 块的相关案例 141 6.3.2 段的相关案例 144 6.3.3 表空间的案例 148 6.3.4 rowid 151 6.4 本章习题、总结与延伸 153 第7章 且慢,探寻表的设计让SQL飞 154 7.1 表设计 154 7.1.1 表的设计 155 7.1.2 其他补充 155 7.2 表设计与SQL优化 156 7.2.1 表的设计 156 7.2.2 其他补充 179 7.3 相关优化案例分析 184 7.3.1 分区表相关案例 185 7.3.2 全局临时表案例 190 7.3.3 监控异常的表设计 195 7.3.4 表设计优化相关案例总结 199 7.4 本章习题、总结与延伸 199 第8章 且慢,学习索引如何让SQL飞 200 8.1 索引知识要点概述 201 8.1.1 索引结构的推理 201 8.1.2 索引特性的提炼 204 8.2 索引SQL优化 206 8.2.1 经典三大特性 207 8.2.2 组合索引选用 217 8.2.3 索引扫描类型的分类与构造 219 8.3 索引相关优化案例 225 8.3.1 三大特性的相关案例 225 8.3.2 组合索引的经典案例 231 8.4 本章习题、总结与延伸 234 第9章 且慢,弄清索引之阻碍让SQL飞 23

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值