# 存储过程 DELIMITER // CREATEPROCEDURE idata() BEGIN DECLARE i INT; SET i=1; WHILE (i <=100000) DO INSERTINTO t VALUES (i, i, i); SET i=i+1; END WHILE; END// DELIMITER ;
# 调用存储过程 CALL idata();
索引树
查询
常规查询
选择索引a,预估的扫描行数为10001
1 2 3 4 5 6
mysql> EXPLAIN SELECT*FROM t WHERE a BETWEEN10000AND20000; +----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+-----------------------+ | id | select_type |table| partitions | type | possible_keys | key | key_len |ref|rows| filtered | Extra | +----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+-----------------------+ |1| SIMPLE | t |NULL|range| a | a |5|NULL|10001|100.00|Using index condition| +----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+-----------------------+
索引选择异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# 返回空集合 mysql> EXPLAIN SELECT*FROM t WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b LIMIT 1; +----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+------------------------------------+ | id | select_type |table| partitions | type | possible_keys | key | key_len |ref|rows| filtered | Extra | +----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+------------------------------------+ |1| SIMPLE | t |NULL|range| a,b | b |5|NULL|50128|1.00|Using index condition; Usingwhere| +----+-------------+-------+------------+-------+---------------+------+---------+------+-------+----------+------------------------------------+
mysql>SELECT*FROM t WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b LIMIT 1; Emptyset (0.07 sec)
# Time: 2019-01-30T11:32:31.335272Z # User@Host: root[root] @ localhost [] Id: 8 # Query_time: 0.046896 Lock_time: 0.000141 Rows_sent: 0 Rows_examined: 50001 SETtimestamp=1548847951; SELECT*FROM t WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b LIMIT 1;
mysql> EXPLAIN SELECT*FROM t FORCE INDEX(a) WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b LIMIT 1; +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+ | id | select_type |table| partitions | type | possible_keys | key | key_len |ref|rows| filtered | Extra | +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+ |1| SIMPLE | t |NULL|range| a | a |5|NULL|1000|11.11|Using index condition; Usingwhere; Using filesort | +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+
mysql>SELECT*FROM t FORCE INDEX(a) WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b LIMIT 1; Emptyset (0.00 sec)
# Time: 2019-01-30T11:32:45.938128Z # User@Host: root[root] @ localhost [] Id: 8 # Query_time: 0.001304 Lock_time: 0.000148 Rows_sent: 0 Rows_examined: 1000 SETtimestamp=1548847965; SELECT*FROM t FORCE INDEX(a) WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b LIMIT 1;
order by b,a
不通用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
mysql> EXPLAIN SELECT*FROM t WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b,a LIMIT 1; +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+ | id | select_type |table| partitions | type | possible_keys | key | key_len |ref|rows| filtered | Extra | +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+ |1| SIMPLE | t |NULL|range| a,b | a |5|NULL|1000|50.00|Using index condition; Usingwhere; Using filesort | +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+
mysql>SELECT*FROM t WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b,a LIMIT 1; Emptyset (0.01 sec)
# Time: 2019-01-30T13:53:18.233163Z # User@Host: root[root] @ localhost [] Id: 8 # Query_time: 0.000609 Lock_time: 0.000191 Rows_sent: 1 Rows_examined: 0 SETtimestamp=1548856398; EXPLAIN SELECT*FROM t WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b,a LIMIT 1;
order by b,a要求按照b,a排序,那扫描行数成为了影响优化器决策的主要条件,此时会选择只需扫描1000行的索引a
但这并非通用优化手段,只是恰好order by b limit 1和order by b,a limit 1都是返回b中最小的一行,语义一致而已
limit 100
不通用
1 2 3 4 5 6 7
mysql> EXPLAIN SELECT*FROM (SELECT*FROM t WHERE (a BETWEEN1AND1000) AND (b BETWEEN50000AND100000) ORDERBY b LIMIT 100) alias LIMIT 1; +----+-------------+------------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+ | id | select_type |table| partitions | type | possible_keys | key | key_len |ref|rows| filtered | Extra | +----+-------------+------------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+ |1|PRIMARY|<derived2>|NULL|ALL|NULL|NULL|NULL|NULL|100|100.00|NULL| |2| DERIVED | t |NULL|range| a,b | a |5|NULL|1000|50.00|Using index condition; Usingwhere; Using filesort | +----+-------------+------------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------------------------+