为什么MySQL不使用索引?

时间:2015-08-17 11:01:12

标签: mysql indexing

我有两个表:(省略与此问题无关的列):

CREATE TABLE 'oc_room' (
  'id' int(11) NOT NULL AUTO_INCREMENT,
  'house_id' int(11) NOT NULL,
  'style_id' int(11) DEFAULT NULL,
  'weight' int(11) DEFAULT '0',
  'state' tinyint(4) DEFAULT '0',
  -- (more columns, omitted for clarity)
  PRIMARY KEY ('id'),
  KEY 'house_id' ('house_id'),
  KEY 'style_id' ('style_id'),
  KEY 'butler_id' ('butler_id'),
  KEY 'oc_room_house_state_hidden_ik_1' ('house_id','state','hidden'),
  CONSTRAINT 'oc_room_ibfk_1' FOREIGN KEY ('house_id') REFERENCES 'oc_house' ('id'),
  CONSTRAINT 'oc_room_ibfk_2' FOREIGN KEY ('style_id') REFERENCES 'oc_room_style' ('id'),
  CONSTRAINT 'oc_room_ibfk_3' FOREIGN KEY ('butler_id') REFERENCES 'oc_butler' ('id')
) ENGINE=InnoDB AUTO_INCREMENT=267 DEFAULT CHARSET=utf8;

CREATE TABLE 'oc_circle_of_community' (
  'id' int(11) NOT NULL AUTO_INCREMENT,
  'circle_id' int(11) NOT NULL,
  'community_id' int(11) NOT NULL,
  PRIMARY KEY ('id'),
  KEY 'circle_id' ('circle_id'),
  KEY 'community_id' ('community_id'),
  CONSTRAINT 'oc_circle_of_community_ibfk_1' FOREIGN KEY ('circle_id') REFERENCES 'oc_circle' ('id'),
  CONSTRAINT 'oc_circle_of_community_ibfk_2' FOREIGN KEY ('community_id') REFERENCES 'oc_community' ('id')
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

当我explain选择陈述时,我有两个问题

问题1:

让我们从两张图片开始:

PIC-1: enter image description here

PIC-2: enter image description here 请特别注意explain输出的底线。

然后将PIC-1中的表与PIC-2中的表进行比较。你会发现:

  1. PIC-1中oc_room的选择使用组合键oc_room_house_state_hidden_ik_1
  2. 然后在PIC-2中,不使用密钥。
  3. 两个陈述之间的唯一区别是oc_room.id in (5,7,9,20,40,60 )已取代
  4. oc_room.id in 
       ( select id 
           from oc_house
           where community_id in 
         ( select community_id
             from oc_circle_of_community
            where circle_id in
          ( select id 
              from oc_circle
             where oc_circle.district_id in
             ( select id
                 from oc_district
                where oc_district.id = 3 ))))  
    

    为什么会有差异?

    oc_room中共有约300行。

    问题2:

    查看表格的第2行PIC-2,其中解释了表格oc_circle_of_community的选择。有两种可能的键:circle_idcommunity_id。为什么不使用两把钥匙?
    (表oc_circle_of_community中共有14行。这可能会有所帮助。)

2 个答案:

答案 0 :(得分:1)

来自bottom的手册。

  

索引对于小型表或大型表的查询不太重要   报表查询处理大多数或所有行的位置。当一个查询   需要访问大多数行,顺序读取比快   通过索引工作。顺序读取可以最大限度地减少磁盘搜索   如果不是查询所需的所有行。

PIC-1

a)300行的数量太小,无法在单个索引上进行磨练,然后进行扫描,以便根据索引中断,或者

b)您尝试使用足够的复合索引,或

c)你用covering index寻找黄金并避免数据页读取

注意,它解决了8行,而不是300行。它采用了复合(house_idstatehidden),其中最后一行没有显示你。总共7个字节。

由于您只有300行,analyze table应该只需要一秒钟。它刷新了关键分布的统计数据,而不是变得陈旧,从而迫使密钥不被使用。密钥可能是使用目标,但最终在执行期间被放弃。因此,它是关于其有用性的一般声明,例如对于大表,而不是您的问题。

PIC-2

REF为NULL的14行与本答案的开头有关。

答案 1 :(得分:0)

第一个查询使用索引,因为它是"覆盖"。也就是说,SELECT中的所有字段都在该索引中:

  • 索引键:house_id,state,hidden
  • 隐式添加的主键:id

好吧,我错了。它说Using index condition,指的是Index Condition Pushdown;它没有说Using index,这意味着"覆盖"。 ORDER BY weight...阻止"覆盖"。要获得更多信息,请EXPLAIN FORMAT=JSON SELECT ...

对于第二个查询,请勿使用IN ( SELECT ... ),它会非常优化非常。相反,变成JOIN。完成后,如果仍有必要,我们可以讨论它的性能。

我们可能会发现它仍然没有使用索引,但是运行得足够快,不用担心。

复合索引应该启动,其中任何列都是" =常量" (hidden,在第一个查询中)。优化器不会处理多个"范围"同时,可能处理IN ( constants )。我Index Cookbook中的更多讨论。

(无关...)

难道state不能为空吗?

相关问题