探究MySQL优化器对索引和JOIN顺序的选择

2019-01-05 09:50:30丽君

2.3.3 穷举

   JOIN的第一个表可以是:A或者B;如果第一个表选择了A,第二个表可以选择B;如果第一个表选择了B,第二个表可以选择A;

   因为前面的排序,B表的found records更少,所以JOIN顺序穷举时的第一个表先选择B(这个是有讲究的)。

(*) 选择第一个JOIN的表为B
  (**) 确定B表的访问方式
    因为B表为第一个表,所以无法使用索引IND_D(B.DepartmentID = A.DepartmentID),而只能使用IND_DN(B.DepartmentName = 'TBX')
      使用IND_DN索引的成本计算:1.2;其中IO成本为1。
      是否使用全表扫描:这里会比较使用索引的IO成本和全表扫描的IO成本,前者为1,后者为2;所以忽略全表扫描
    所以,B表的访问方式ref,使用索引IND_D

  (**) 从剩余的表中穷举选出第二个JOIN的表,这里剩余的表为:A
  (**) 将A表加入JOIN,并确定其访问方式
    可以使用的索引为:`IND_L_D`(A.LastName = 'zhou')或者`IND_DID`(B.DepartmentID = A.DepartmentID)
    依次计算使用索引IND_L_D、IND_DID的成本:
    (***) IND_L_D A.LastName = 'zhou'
          在range analysis阶段给出了A.LastName = 'zhou'对应的记录约为:51。
          所以,计算IO成本为:51;ref做IO成本计算时会做一次修正,将其修正为worst_seek(参考)
          修正后IO成本为:15,总成本为:25.2
    (***) IND_DID B.DepartmentID = A.DepartmentID
          这是一个需要知道前面表的结果,才能计算的成本。所以range analysis是无法分析的
          这里,我们看到前面表为B,found_record是1,所以A.DepartmentID只需要对应一条记录就可以了
          因为具体取值不知道,也没有直方图,所以只能简单依据索引统计信息来计算:
            索引IND_DID的列A.DepartmentID的Cardinality为1349,全表记录数为1349
            所以,每一个值对应一条记录,而前面表B只有一条记录,所以这里的found_record计算为1*1 = 1
            所以IO成本为:1,总成本为1.2
    (***) IND_L_D成本为25.2;IND_DID成本为1.2,所以选择后者为当前表的访问方式
  (**) 确定A使用索引IND_DID,访问方式为ref
  (**) JOIN顺序B|A,总成本为:1.2+1.2 = 2.4