我有两个表:(省略了与这个问题无关的列):
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;
当我解释
一个选择语句时,我有两个问题
问题一:
让我们从两张图片开始:
然后将PIC-1中的表格与PIC-2中的表格进行比较。你会发现:
- PIC-1 中
oc_room
的选择使用组合键oc_room_house_state_hidden_ik_1
。 - 那么在PIC-2中,没有用到key。
- 两个语句的唯一区别是
oc_room.id in (5,7,9,20,40,60 )
被替换
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:
查看表的 PIC-2,第 2 行,它解释了表 oc_circle_of_community
的选择。有两个可能的键:circle_id
和 community_id
。为什么这两个键不能用?
(表 oc_circle_of_community
中共有 14 行。这可能会有所帮助。)
最佳答案
来自 bottom 处的手册.
Indexes are less important for queries on small tables, or big tables where report queries process most or all of the rows. When a query needs to access most of the rows, reading sequentially is faster than working through an index. Sequential reads minimize disk seeks, even if not all the rows are needed for the query.
图片-1
a) 300 行对于它来说太小了,无法在单个索引上进行磨练并随后进行扫描,因此它根本不会关心索引,或者
b) 你试图使用一个足够的复合索引,或者
c) 你用 covering index 去拿金牌并避免读取数据页
但是注意,它在 8 行中解决了它,而不是 300。它与复合 (house_id
,state
,hidden
),最后一个不是你显示的。总共 7 个字节宽。
因为您只有 300 行,analyze table
应该需要一瞬间。它刷新可能变得陈旧的 key 分布的统计数据,从而强制不使用 key 。 key 可能是使用目标,但最终在执行期间被放弃。因此,这是关于其用途的一般性陈述,例如对于大型表格,而不是您的问题。
图片-2
REF NULL 的 14 行与本答案的开头有关。
关于mysql - 为什么MySQL不使用索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32048691/