博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MySQL的索引策略(1)
阅读量:6611 次
发布时间:2019-06-24

本文共 3398 字,大约阅读时间需要 11 分钟。

hot3.png

索引提供了快速的查询方案,同时增加了删除、修改的开销;续上一篇博客《MySQL索引基础》,根据索引的优缺点,本文列举一些高效的MySQL策略。

  • 不参与计算

select id from table where id+1<10

select * from table where to_days(current_data)-to_days(date) <=10

类似上述查询,将索引列写进数学表达式,或者作为函数的一部分,都会引起索引失效。

  • 前缀索引

​​​​​​​上篇博客提到了模拟哈希索引在长值字段的应用。类似情况,还可以使用前缀索引,即只对字段开始的前n个字符建立索引。前缀索引是牺牲索引选择性,换取建立索引效率的方案。索引选择性是衡量索引对字段区分能力的指标,即 count(distinct(column))/count(*);选择性越大,对数据的区分度越好,则查询效率越高。例如,对美国城市名做前缀索引,取三位,则San字段会有很多重复名(旧金山、圣塔芭芭拉),整体选择性会下降。除了索引的选择性,还要考虑前缀的分布情况,尽量均匀,或者在高频查询的数据行有良好的区分性。

MySQL无法基于前缀索引做ORDER BY和GROUP BY操作。逆序字符串的前缀索引就变成了后缀索引,在电子邮箱查询等特定场景有不错的效果。

  • 多列索引

​​​​​​​多条件查询很常见,此时就需要建立多列索引。尤其是OR操作,耗费大量资源用于缓存、排序、合并,这些都不会被优化器计算进查询成本,影响并发性。可以用 EXPLAIN ${SQL}查看,如果有索引合并,也说明这种场景需要多列索引。

多列索引需要合理的顺序,以满足:1. 尽可能快地查讯 2.满足ORDER BY和GROUP BY操作  3.尽量满足覆盖索引。

简单地,可以讲选择性最高的列放在最左。

mysql> SELECT SUM(staff_id = 2), SUM(customer_id = 584) FROM payment\G*************************** 1. row ***************************SUM(staff_id = 2): 7992SUM(customer_id = 584): 30mysql> SELECT SUM(staff_id = 2) FROM payment WHERE customer_id = 584\G*************************** 1. row ***************************SUM(staff_id = 2): 17mysql> SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,> COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,> COUNT(*)> FROM payment\G*************************** 1. row ***************************staff_id_selectivity: 0.0001customer_id_selectivity: 0.0373COUNT(*): 16049

第一个查询表明,customer_id为584对应的行更少。第二个查询说明在customer_id=584时,staff_id具有良好的选择性。第三个查询显示,整体上,customer_id具有更好的选择性。所以这个例子符合选择性最高的列放在最左的原则。需要注意,查询1和2的结果,依赖于选定的具体值,可能会对其他值产生偏见

mysql> EXPLAIN SELECT COUNT(DISTINCT threadId) AS COUNT_VALUE-> FROM Message-> WHERE (groupId = 10137) AND (userId = 1288826) AND (anonymous = 0)-> ORDER BY priority DESC, modifiedDate DESCid: 1select_type: SIMPLEtable: Messagetype: refkey: ix_groupId_userIdkey_len: 18ref: const,constrows: 1251162Extra: Using wheremysql> SELECT COUNT(*), SUM(groupId = 10137),-> SUM(userId = 1288826), SUM(anonymous = 0)-> FROM Message\G*************************** 1. row ***************************count(*): 4142217sum(groupId = 10137): 4092654sum(userId = 1288826): 1288496sum(anonymous = 0): 4141934

第一个查询显示,该表有一个(groupId, userId)的联合索引。但第二个查询表明,这两列上的索引选择性都很低,基本失效。这类问题不能在数据库层面解决,需要在业务上特殊处理这些用户和组,比如禁止相关id查询这条SQL。这类问题比较普遍,比如对所有访客固定一个ID,或者拥有大量好友、评论等的用户。

还有一个重要的原则,考察该表上执行各类条件查询的频率,其相关字段是建立联合索引的重要依据。

  • 聚簇索引

​​​​​​​聚簇索引是一种存储方式,InnoDB中,在同一个结构中保存了索引和数据行。即非叶节点保存索引,叶子节点保存数据,与B+树的定义一致。InnoDB通过主键聚集数据,也就是对主键列聚簇索引。聚簇索引的优势如下:

  1. 相关数据连续存储(减少磁盘IO)。例如,邮箱数据,以用户id为主键,可以用较少的IO取出与某用户所有往来邮件。
  2. 访问速度更快。数据与索引在同一个树中。
  3. 可以直接使用叶子页中的主键值。

​​​​​​​聚簇索引的缺陷如下:

  1. 如果所有数据都放进内存,那么访问顺序的影响就会变小。
  2. 插入顺序影响插入速度;以主键顺序的插入的速度最快。
  3. 更新代价很高。会把对应行移动到新位置,其他行的位置跟着改变。
  4. 插入或者更新,某列插入已满的页,则需要分裂页,占用更大的空间。
  5. 导致全表扫描变慢。
  6. 二级索引(即非聚簇索引)更大,因为在叶子节点包含了引用行的主键列。所以二级索引的工作顺序是:在二级索引中查找主键->在聚簇索引中查找行,所以做了两次B+树搜索(顾名思义?)。

简单说,聚簇索引只能索引一列,通常是主键;所有数据是按照聚簇索引列的顺序连续排列的。

​​​​​​​以下表为例,对比一下InnoDB聚簇索引和MyISAM中数据存储的方式。

CREATE TABLE layout_test (col1 int NOT NULL,col2 int NOT NULL,PRIMARY KEY(col1),KEY(col2));

假设col1的值在1-10000,在磁盘上行的顺序随机;col2取值在1-100,有很多重复值。

MyISAM按照插入顺序存储。

233542_w77V_3728287.png

这种方式可以直接根据行号查找到数据,索引中只需保存行号。主键索引和col2索引如下图:

233857_Occ7_3728287.png233859_zrcX_3728287.png

MyISAM的主键索引与其他列的索引并无差异;不过是满足了唯一、为空的索引。

InnoDB支持聚簇索引,其索引和数据分布情况如下图。

234225_Vr5A_3728287.png

一个显著的不同是 ,聚簇索引存储了整张表;即使主键是列前缀也如此。

回滚指针用于事务和MVCC。

InnoDB的二级索引与主键索引不同。

234451_Y8eH_3728287.png

用主键值代替“行指针”的优势是,非主键列的插入、更新不会引起大量移动、也分裂;缺陷是占用了更大的存储空间。这两者在数据存储时的对比,可抽象为下图。

234811_FITn_3728287.png

基于插入性能的考虑,InnoDB表的主键可以定义为自增列。一方面保证了顺序写入,另一方面在主键关联时性能也更好。同时,还能节约索引空间。

其他几类索引策略将在下一篇博客中介绍。

 

转载于:https://my.oschina.net/u/3728287/blog/1577030

你可能感兴趣的文章
MySQL学习笔记_5_SQL语言的设计与编写(上)
查看>>
2005上半年网络工程师上午试题分析与解答
查看>>
Exchange的安全问题(一)
查看>>
C# winform中自定义用户控件 然后在页面中调用用户控件的事件
查看>>
Yii2使用驼峰命名的形式访问控制器
查看>>
[react-native] 华为真机安装失败解决方法
查看>>
Confirm the Ending
查看>>
17. Debuggers (调试器 5个)
查看>>
toUperCase() 与 toLowerCase()
查看>>
python2.7安装requests
查看>>
2007舜宇杯ACM程序设计浙江省赛结果
查看>>
makefile学习笔记
查看>>
SpringMVC (九)重定向和转发
查看>>
php知识点总结(一)
查看>>
Linux改变文件或目录的访问权限命令
查看>>
20190412
查看>>
linux之SQL语句简明教程---UPDATE DELETE FROM
查看>>
ES6新特性3:函数的扩展
查看>>
不忘初心——2017MIAC安全赛小记
查看>>
高速pcb布线技巧
查看>>