索引提供了快速的查询方案,同时增长了删除、修改的开销;续上一篇博客《MySQL索引基础》,根据索引的优缺点,本文列举一些高效的MySQL策略。mysql
select id from table where id+1<10sql
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.尽可能知足覆盖索引。优化
简单地,能够讲选择性最高的列放在最左。spa
mysql> SELECT SUM(staff_id = 2), SUM(customer_id = 584) FROM payment\G *************************** 1. row *************************** SUM(staff_id = 2): 7992 SUM(customer_id = 584): 30 mysql> SELECT SUM(staff_id = 2) FROM payment WHERE customer_id = 584\G *************************** 1. row *************************** SUM(staff_id = 2): 17 mysql> 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.0001 customer_id_selectivity: 0.0373 COUNT(*): 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 DESC id: 1 select_type: SIMPLE table: Message type: ref key: ix_groupId_userId key_len: 18 ref: const,const rows: 1251162 Extra: Using where mysql> SELECT COUNT(*), SUM(groupId = 10137), -> SUM(userId = 1288826), SUM(anonymous = 0) -> FROM Message\G *************************** 1. row *************************** count(*): 4142217 sum(groupId = 10137): 4092654 sum(userId = 1288826): 1288496 sum(anonymous = 0): 4141934
第一个查询显示,该表有一个(groupId, userId)的联合索引。但第二个查询代表,这两列上的索引选择性都很低,基本失效。这类问题不能在数据库层面解决,须要在业务上特殊处理这些用户和组,好比禁止相关id查询这条SQL。这类问题比较广泛,好比对全部访客固定一个ID,或者拥有大量好友、评论等的用户。
还有一个重要的原则,考察该表上执行各种条件查询的频率,其相关字段是创建联合索引的重要依据。
聚簇索引是一种存储方式,InnoDB中,在同一个结构中保存了索引和数据行。即非叶节点保存索引,叶子节点保存数据,与B+树的定义一致。InnoDB经过主键汇集数据,也就是对主键列聚簇索引。聚簇索引的优点以下:
聚簇索引的缺陷以下:
简单说,聚簇索引只能索引一列,一般是主键;全部数据是按照聚簇索引列的顺序连续排列的。
如下表为例,对比一下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按照插入顺序存储。
这种方式能够直接根据行号查找到数据,索引中只需保存行号。主键索引和col2索引以下图:
MyISAM的主键索引与其余列的索引并没有差别;不过是知足了惟1、为空的索引。
InnoDB支持聚簇索引,其索引和数据分布状况以下图。
一个显著的不一样是 ,聚簇索引存储了整张表;即便主键是列前缀也如此。
回滚指针用于事务和MVCC。
InnoDB的二级索引与主键索引不一样。
用主键值代替“行指针”的优点是,非主键列的插入、更新不会引发大量移动、也分裂;缺陷是占用了更大的存储空间。这二者在数据存储时的对比,可抽象为下图。
基于插入性能的考虑,InnoDB表的主键能够定义为自增列。一方面保证了顺序写入,另外一方面在主键关联时性能也更好。同时,还能节约索引空间。
其余几类索引策略将在下一篇博客中介绍。