美文网首页
2019-05-10单表索引类型

2019-05-10单表索引类型

作者: 括儿之家 | 来源:发表于2019-06-17 10:05 被阅读0次

    const

        通过主键列来定位一条记录 例如:SELECT * FROM single_table WHERE id = 1438;

    ref

        某个普通的二级索引列与常数进行等值比较  SELECT * FROM single_table WHERE key1 = 'abc';

    ref_or_null

        找出某个二级索引列的值等于某个常数的记录,还想把该列的值为NULL的记录也找出来

        SELECT * FROM single_demo WHERE key1 = 'abc' OR key1 IS NULL;

    range

        利用索引进行范围匹配的访问方法称之为:range

        SELECT * FROM single_table WHERE key2 IN (1438, 6328) OR (key2 >= 38 AND key2 <= 79);

    index    

        联合索引 查询第一个字段时 使用index

        SELECT key_part1, key_part2, key_part3 FROM single_table WHERE key_part2 = 'abc';

    all 

        最直接的查询执行方式就是我们已经提了无数遍的全表扫描,对于InnoDB表来说也就是直接扫描聚簇索引,设计MySQL的大叔把这种使用全表扫描执行查询的方式称之为:all

    二级索引 + 回表

    一般情况下只能利用单个二级索引执行查询,比方说下边的这个查询:

    SELECT * FROM single_table WHERE key1 ='abc'AND key2 > 1000;

    查询优化器会识别到这个查询中的两个搜索条件:

    key1 = 'abc'

    key2 > 1000

    优化器一般会根据single_table表的统计数据来判断到底使用哪个条件到对应的二级索引中查询扫描的行数会更少,选择那个扫描行数较少的条件到对应的二级索引中查询(关于如何比较的细节我们后边的章节中会唠叨)。然后将从该二级索引中查询到的结果经过回表得到完整的用户记录后再根据其余的WHERE条件过滤记录。一般来说,等值查找比范围查找需要扫描的行数更少(也就是ref的访问方法一般比range好,但这也不总是一定的,也可能采用ref访问方法的那个索引列的值为特定值的行数特别多),所以这里假设优化器决定使用idx_key1索引进行查询,那么整个查询过程可以分为两个步骤:

    步骤1:使用二级索引定位记录的阶段,也就是根据条件key1 = 'abc'从idx_key1索引代表的B+树中找到对应的二级索引记录。

    步骤2:回表阶段,也就是根据上一步骤中找到的记录的主键值进行回表操作,也就是到聚簇索引中找到对应的完整的用户记录,再根据条件key2 > 1000到完整的用户记录继续过滤。将最终符合过滤条件的记录返回给用户。

    这里需要特别提醒大家的一点是,因为二级索引的节点中的记录只包含索引列和主键,所以在步骤1中使用idx_key1索引进行查询时只会用到与key1列有关的搜索条件,其余条件,比如key2 > 1000这个条件在步骤1中是用不到的,只有在步骤2完成回表操作后才能继续针对完整的用户记录中继续过滤。

    明确range访问方法使用的范围区间

    其实对于B+树索引来说,只要索引列和常数使用=、<=>、IN、NOT IN、IS NULL、IS NOT NULL、>、<、>=、<=、BETWEEN、!=(不等于也可以写成<>)或者LIKE操作符连接起来,就可以产生一个所谓的区间。

    小贴士: LIKE操作符比较特殊,只有在匹配完整字符串或者匹配字符串前缀时才可以利用索引,具体原因我们在前边的章节中唠叨过了,这里就不赘述了。 IN操作符的效果和若干个等值匹配操作符`=`之间用`OR`连接起来是一样的,也就是说会产生多个单点区间,比如下边这两个语句的效果是一样的: SELECT * FROM single_table WHERE key2 IN (1438, 6328); SELECT * FROM single_table WHERE key2 = 1438 OR key2 = 6328;

    不过在日常的工作中,一个查询的WHERE子句可能有很多个小的搜索条件,这些搜索条件需要使用AND或者OR操作符连接起来

    索引合并

    我们前边说过MySQL在一般情况下执行一个查询时最多只会用到单个二级索引,但不是还有特殊情况么,在这些特殊情况下也可能在一个查询中使用到多个二级索引,设计MySQL的大叔把这种使用到多个索引来完成一次查询的执行方法称之为:index merge,具体的索引合并算法有下边三种。

    Intersection合并

    Intersection翻译过来的意思是交集。这里是说某个查询可以使用多个二级索引,将从多个二级索引中查询到的结果取交集,比方说下边这个查询:

    SELECT * FROM single_table WHERE key1 ='a'AND key3 ='b';

    假设这个查询使用Intersection合并的方式执行的话,那这个过程就是这样的:

    从idx_key1二级索引对应的B+树中取出key1 = 'a'的相关记录。

    从idx_key3二级索引对应的B+树中取出key3 = 'b'的相关记录。

    二级索引的记录都是由索引列 + 主键构成的,所以我们可以计算出这两个结果集中id值的交集。

    按照上一步生成的id值列表进行回表操作,也就是从聚簇索引中把指定id值的完整用户记录取出来,返回给用户。

    这里有同学会思考:为啥不直接使用idx_key1或者idx_key3只根据某个搜索条件去读取一个二级索引,然后回表后再过滤另外一个搜索条件呢?这里要分析一下两种查询执行方式之间需要的成本代价。

    只读取一个二级索引的成本:

    按照某个搜索条件读取一个二级索引

    根据从该二级索引得到的主键值进行回表操作,然后再过滤其他的搜索条件

    读取多个二级索引之后取交集成本:

    按照不同的搜索条件分别读取不同的二级索引

    将从多个二级索引得到的主键值取交集,然后进行回表操作

    虽然读取多个二级索引比读取一个二级索引消耗性能,但是读取二级索引的操作是顺序I/O,而回表操作是随机I/O,所以如果只读取一个二级索引时需要回表的记录数特别多,而读取多个二级索引之后取交集的记录数非常少,当节省的因为回表而造成的性能损耗比访问多个二级索引带来的性能损耗更高时,读取多个二级索引后取交集比只读取一个二级索引的成本更低。

    Union合并

    我们在写查询语句时经常想把既符合某个搜索条件的记录取出来,也把符合另外的某个搜索条件的记录取出来,我们说这些不同的搜索条件之间是OR关系。有时候OR关系的不同搜索条件会使用到不同的索引,比方说这样:

    SELECT * FROM single_table WHERE key1 ='a'OR key3 ='b'

    Intersection是交集的意思,这适用于使用不同索引的搜索条件之间使用AND连接起来的情况;Union是并集的意思,适用于使用不同索引的搜索条件之间使用OR连接起来的情况。与Intersection索引合并类似,MySQL在某些特定的情况下才可能会使用到Union索引合并:

    情况一:二级索引列是等值匹配的情况,对于联合索引来说,在联合索引中的每个列都必须等值匹配,不能出现只出现匹配部分列的情况。

    相关文章

      网友评论

          本文标题:2019-05-10单表索引类型

          本文链接:https://www.haomeiwen.com/subject/fmdaoqtx.html