For a single-part index, index value intervals can be
conveniently represented by corresponding conditions in the
WHERE
clause, so we'll talk about
range conditions rather than
“intervals”.
The definition of a range condition for a single-part index is as follows:
For both BTREE
and
HASH
indexes, comparison of a key part
with a constant value is a range condition when using the
=
, <=>
,
IN
, IS NULL
, or
IS NOT NULL
operators.
For BTREE
indexes, comparison of a key
part with a constant value is a range condition when using
the >
, <
,
>=
, <=
,
BETWEEN
, !=
, or
<>
operators, or LIKE
'
(where
pattern
''
doesn't start with a wildcard).
pattern
'
For all types of indexes, multiple range conditions
combined with OR
or
AND
form a range condition.
“Constant value” in the preceding descriptions means one of the following:
A constant from the query string
A column of a const
or
system
table from the same join
The result of an uncorrelated subquery
Any expression composed entirely from subexpressions of the preceding types
Here are some examples of queries with range conditions in the
WHERE
clause:
SELECT * FROM t1 WHEREkey_col
> 1 ANDkey_col
< 10; SELECT * FROM t1 WHEREkey_col
= 1 ORkey_col
IN (15,18,20); SELECT * FROM t1 WHEREkey_col
LIKE 'ab%' ORkey_col
BETWEEN 'bar' AND 'foo';
Note that some non-constant values may be converted to constants during the constant propagation phase.
MySQL tries to extract range conditions from the
WHERE
clause for each of the possible
indexes. During the extraction process, conditions that can't
be used for constructing the range condition are dropped,
conditions that produce overlapping ranges are combined, and
conditions that produce empty ranges are removed.
For example, consider the following statement, where
key1
is an indexed column and
nonkey
is not indexed:
SELECT * FROM t1 WHERE (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR (key1 < 'bar' AND nonkey = 4) OR (key1 < 'uux' AND key1 > 'z');
The extraction process for key key1
is as
follows:
Start with original WHERE
clause:
(key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR (key1 < 'bar' AND nonkey = 4) OR (key1 < 'uux' AND key1 > 'z')
Remove nonkey = 4
and key1
LIKE '%b'
because they cannot be used for a
range scan. The right way to remove them is to replace
them with TRUE
, so that we don't miss
any matching records when doing the range scan. Having
replaced them with TRUE
, we get:
(key1 < 'abc' AND (key1 LIKE 'abcde%' OR TRUE)) OR (key1 < 'bar' AND TRUE) OR (key1 < 'uux' AND key1 > 'z')
Collapse conditions that are always true or false:
(key1 LIKE 'abcde%' OR TRUE)
is
always true
(key1 < 'uux' AND key1 > 'z')
is always false
Replacing these conditions with constants, we get:
(key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)
Removing unnecessary TRUE
and
FALSE
constants, we obtain
(key1 < 'abc') OR (key1 < 'bar')
Combining overlapping intervals into one yields the final condition to be used for the range scan:
(key1 < 'bar')
In general (and as demonstrated in the example), the condition
used for a range scan is less restrictive than the
WHERE
clause. MySQL performs an additional
check to filter out rows that satisfy the range condition but
not the full WHERE
clause.
The range condition extraction algorithm can handle nested
AND
/OR
constructs of
arbitrary depth, and its output doesn't depend on the order in
which conditions appear in WHERE
clause.
Ésta es una traducción del manual de referencia de MySQL, que puede encontrarse en dev.mysql.com. El manual de referencia original de MySQL está escrito en inglés, y esta traducción no necesariamente está tan actualizada como la versión original. Para cualquier sugerencia sobre la traducción y para señalar errores de cualquier tipo, no dude en dirigirse a mysql-es@vespito.com.