热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[慢查优化]建索引时注意字段选择性&范围查询注意组合_MySQL

[慢查优化]建索引时注意字段选择性amp;amp;范围查询注意组合索引的字段顺序
bitsCN.com 写在前面的话:
  1. 之前曾说过“不要求每个人一定理解 联表查询(join/left join/inner join等)时的mysql运算过程”,但对于字段选择性差意味着什么,组合索引字段顺序意味着什么,要求每个人必须了解;
  2. 重复上一次的话:把mysql客户端(如SQLyog,如HeidiSQL)放在桌面上,时不时拿出来 explain 一把,这是一种美德!
    • 确保亲手查过SQL的执行计划,一定要注意看执行计划里的 possible_keys、key和rows这三个值,让影响行数尽量少,保证使用到正确的索引,减少不必要的Using temporary/Using filesort;
  3. 不要在选择性非常差的字段上建索引,原因参见优化策略A;
  4. 查询条件里出现范围查询(如A>7,A in (2,3))时,要警惕,不要建了组合索引却完全用不上,原因参见优化策略B;

我们先回顾一下字段选择性的基础知识。

——字段选择性的基础知识——

引子:什么字段都可以建索引吗?

如下表所示,sort 字段的选择性非常差,你可以执行 show index from ads 命令可以看到 sort 的 Cardinality(散列程度)只有 9,这种字段上本不应该建索引:

Table

Non_unique

Key_name

Seq_in_index

Column_name

Collation

Cardinality

Sub_part

Packed

Null

Index_type

Comment

ads

1

sort

1

sort

A

9

/N

/N

 

BTREE

 

优化策略A:字段选择性
  • 选择性较低索引 可能带来的性能问题
    • 索引选择性=索引列唯一值/表记录数;
    • 选择性越高索引检索价值越高,消耗系统资源越少;选择性越低索引检索价值越低,消耗系统资源越多;
  • 查询条件含有多个字段时,不要在选择性很低字段上创建索引
    • 可通过创建组合索引来增强低字段选择性和避免选择性很低字段创建索引带来副作用;
    • 尽量减少possible_keys,正确索引会提高sql查询速度,过多索引会增加优化器选择索引的代价,不要滥用索引;

再回顾组合索引与范围查询的业务场景。

——组合索引字段顺序与范围查询之间的关系——

引子:范围查询 city_id in (0,8,10) 能用组合索引 (ads_id,city_id) 吗?

举例,

ac 表有一个组合索引(ads_id,city_id)。

那么如下 ac.city_id IN (0, 8005) 查询条件能用到 ac表的组合索引(ads_id,city_id) 吗?

EXPLAIN

SELECT ac.ads_id

FROM ads, ac

WHERE

ads.id = ac.ads_id

AND ac.city_id IN (0, 8005)

AND ads.status = 'online'

AND ac.start_time

AND ac.end_time>UNIX_TIMESTAMP()

优化策略B:

由于 mysql 索引是基于 B-Tree 的,所以组合索引有“字段顺序”概念。

所以,查询条件中有 ac.city_id IN (0, 8005),而组合索引是 (ads_id,city_id),则该查询无法使用到这个组合索引。

DBA总结道:

组合索引查询的各种场景兹有 Index (A,B,C) ——组合索引多字段是有序的,并且是个完整的BTree 索引。
  • 下面条件可以用上该组合索引查询:
    • A>5
    • A=5 AND B>6
    • A=5 AND B=6 AND C=7
    • A=5 AND B IN (2,3) AND C>5
  • 下面条件将不能用上组合索引查询:
    • B>5 ——查询条件不包含组合索引首列字段
    • B=6 AND C=7 ——查询条件不包含组合索引首列字段
  • 下面条件将能用上部分组合索引查询:
    • A>5 AND B=2 ——当范围查询使用第一列,查询条件仅仅能使用第一列
    • A=5 AND B>6 AND C=2 ——范围查询使用第二列,查询条件仅仅能使用前二列
组合索引排序的各种场景兹有组合索引 Index(A,B)。
  • 下面条件可以用上组合索引排序:
    • ORDER BY A——首列排序
    • A=5 ORDER BY B——第一列过滤后第二列排序
    • ORDER BY A DESC, B DESC——注意,此时两列以相同顺序排序
    • A>5 ORDER BY A——数据检索和排序都在第一列
  • 下面条件不能用上组合索引排序:
    • ORDER BY B ——排序在索引的第二列
    • A>5 ORDER BY B ——范围查询在第一列,排序在第二列
    • A IN(1,2) ORDER BY B ——理由同上
    • ORDER BY A ASC, B DESC ——注意,此时两列以不同顺序排序
顺着组合索引怎么建继续往下延伸,请各位注意“索引合并”概念:
  • MySQL 5,0以下版本,SQL查询时,一张表只能用一个索引(use at most only one index for each referenced table),
  • 从 MySQL 5.0开始,引入了 index merge 概念,包括 Index Merge Union Access Algorithm(多个索引并集访问),包括Index Merge Intersection Access Algorithm(多个索引交集访问),可以在一个SQL查询里用到一张表里的多个索引。
  • MySQL 在5.6.7之前,使用 index merge 有一个重要的前提条件:没有 range 可以使用。[出自参考资源2]
索引合并的简单说明:
  • MySQL 索引合并能使用多个索引
    • SELECT * FROM TB WHERE A=5 AND B=6
      • 能分别使用索引(A) 和 (B) 或 索引合并;
      • 创建组合索引(A,B) 更好;
    • SELECT * FROM TB WHERE A=5 OR B=6
      • 能分别使用索引(A) 和 (B) 或 索引合并;
      • 组合索引(A,B)不能用于此查询,分别创建索引(A) 和 (B)会更好;
最后的总结:仍然是强调再强调:
记住,explain 后再提测是一种美德!

参考资源:1)中文译稿,2013,MySQL 索引最佳实践之问题反馈;2)orczhou,2013,MySQL优化器:index merge介绍;3)orczhou,2013,index merge的补充说明;4)zhengyun,2013,[慢查优化]联表查询注意谁是驱动表 & 你搞不清楚谁join谁更好时请放手让mysql自行判定;5)nocode,2013,MySQL Internals-Index Merge优化;
赠图1枚:转:喵了个咪的,老板催我去重构遗留的 Python 代码……http://ww2.sinaimg.cn/bmiddle/7cc829d3jw1e8qihxzpebg20af07yx6p.gifbitsCN.com
推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Python字典推导式及循环列表生成字典方法
    本文介绍了Python中使用字典推导式和循环列表生成字典的方法,包括通过循环列表生成相应的字典,并给出了执行结果。详细讲解了代码实现过程。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Oracle Database 10g许可授予信息及高级功能详解
    本文介绍了Oracle Database 10g许可授予信息及其中的高级功能,包括数据库优化数据包、SQL访问指导、SQL优化指导、SQL优化集和重组对象。同时提供了详细说明,指导用户在Oracle Database 10g中如何使用这些功能。 ... [详细]
  • 本文介绍了Python版Protobuf的安装和使用方法,包括版本选择、编译配置、示例代码等内容。通过学习本教程,您将了解如何在Python中使用Protobuf进行数据序列化和反序列化操作,以及相关的注意事项和技巧。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • Oracle10g备份导入的方法及注意事项
    本文介绍了使用Oracle10g进行备份导入的方法及相关注意事项,同时还介绍了2019年独角兽企业重金招聘Python工程师的标准。内容包括导出exp命令、删用户、创建数据库、授权等操作,以及导入imp命令的使用。详细介绍了导入时的参数设置,如full、ignore、buffer、commit、feedback等。转载来源于https://my.oschina.net/u/1767754/blog/377593。 ... [详细]
author-avatar
男人着责任
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有