I have two tables: (omitting columns not relevant to this question):
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;
When I explain
a select statement, I have TWO questions
Let's begin with two pictures:
PIC-2: Note in particularr the bottom line of the explain
output.
Then compare the table in PIC-1 with the table in PIC-2. You will find that:
oc_room
in PIC-1 uses the combination-key oc_room_house_state_hidden_ik_1
. oc_room.id in (5,7,9,20,40,60 )
replaced 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 ))))
Why the difference?
There are about 300 rows in table oc_room
in total.
Review the PIC-2, 2rd row of the table, which explains the select of table oc_circle_of_community
. There are two possible keys: circle_id
and community_id
. Why the two keys not be used?
(There are total 14 rows in table oc_circle_of_community
. This may help.)
From the Manual at the 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.
a) the 300 rows is too small a number for it to hone in on a single index and scan thereafter so it aborts caring about indexes at all, or
b) you attempt to use an adequate composite index, or
c) you go for the gold with a covering index and avoid the datapage read
But note , it resolved it in 8 rows, not 300. It went with composite ( house_id
, state
, hidden
), where the last is not shown by you. 7 bytes wide total.
As you only have 300 rows, analyze table
should take a split second. It refreshes the statistics of key distributions than can become stale, thus forcing a key not to be used. A key may be target for use but ultimately abandoned during execution. As such, it is a general statement about its usefulness, such as for large tables, not your issue.
The 14 rows with REF NULL is related to the beginning of this Answer.
The first query uses the index because it is "covering". That is, all the fields in the SELECT
are in that index:
Well, I could be wrong. It says Using index condition
, which refers to Index Condition Pushdown
; it does not say Using index
, which would imply "covering". And the ORDER BY weight...
prevents "covering". To get more insight, do EXPLAIN FORMAT=JSON SELECT ...
.
For the second query, don't use IN ( SELECT ... )
, it optimizes very poorly. Instead, turn into a JOIN
. Once you have done that, we can discuss performance of it, if still necessary.
We will probably find that it is still not using the index, but that is is running fast enough to not worry.
Composite indexes should start with any columns that are "= constant" ( hidden
, in the first query). The optimizer will not deal with multiple "ranges" at the same time, and may not deal well with IN ( constants )
. More discussion in my Index Cookbook .
(Unrelated...)
Shouldn't state
be NOT NULL?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.