在MySQL里,我们一般使用SHOW STATUS查询服务器状态,语法一般来说如下:
SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern' | WHERE expr]
执行命令后会看到很多内容,其中有一部分是Handler_read_*,它们显示了数据库处理SELECT查询语句的状态,对于调试SQL语句有很大意义,可惜实际很多人并不理解它们的实际意义,本文简单介绍一下:
为了让介绍更易懂,先建立一个测试用的表:
CREATE TABLE IF NOT EXISTS `foo` (
`id` int(10) unsigned NOT NULL auto_increment,
`col1` varchar(10) NOT NULL,
`col2` text NOT NULL,
PRIMARY KEY (`id`),
KEY `col1` (`col1`)
);
INSERT INTO `foo` (`id`, `col1`, `col2`) VALUES
(1, 'a', 'a'),
(2, 'b', 'b'),
(3, 'c', 'c'),
(4, 'd', 'd'),
(5, 'e', 'e'),
(6, 'f', 'f'),
(7, 'g', 'g'),
(8, 'h', 'h'),
(9, 'i', 'i');
在下面的测试里,每次执行SQL时按照如下过程执行:
FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler_read%';
EXPLAIN SELECT ...;
Handler_read_first
The number of times the first entry was read from an index. If this value is high, it suggests that the server is doing a lot of full index scans; for example, SELECT col1 FROM foo, assuming that col1 is indexed.
此选项表明SQL是在做一个全索引扫描,注意是全部,而不是部分,所以说如果存在WHERE语句,这个选项是不会变的。如果这个选项的数值很大,既是好事也是坏事。说它好是因为毕竟查询是在索引里完成的,而不是数据文件里,说它坏是因为大数据量时,简便是索引文件,做一次完整的扫描也是很费时的。
FLUSH STATUS;
SELECT col1 FROM foo;
mysql> SHOW SESSION STATUS LIKE 'Handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 1 |
| Handler_read_key | 0 |
| Handler_read_next | 9 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+-------+
6 rows in set (0.00 sec)
mysql> EXPLAIN SELECT col1 FROM foo\G
type: index
Extra: Using index
Handler_read_key
The number of requests to read a row based on a key. If this value is high, it is a good indication that your tables are properly indexed for your queries.
此选项数值如果很高,那么恭喜你,你的系统高效的使用了索引,一切运转良好。
FLUSH STATUS;
SELECT * FROM foo WHERE col1 = 'e';
mysql> SHOW SESSION STATUS LIKE 'Handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 0 |
| Handler_read_key | 1 |
| Handler_read_next | 1 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+-------+
mysql> EXPLAIN SELECT * FROM foo WHERE col1 = 'e'\G
type: ref
Extra: Using where
Handler_read_next
The number of requests to read the next row in key order. This value is incremented if you are querying an index column with a range constraint or if you are doing an index scan.
此选项表明在进行索引扫描时,按照索引从数据文件里取数据的次数。
FLUSH STATUS;
SELECT col1 FROM foo ORDER BY col1 ASC;
mysql> SHOW SESSION STATUS LIKE 'Handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 1 |
| Handler_read_key | 0 |
| Handler_read_next | 9 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+-------+
mysql> EXPLAIN SELECT * FROM foo WHERE col1 = 'e'\G
type: index
Extra: Using index
Handler_read_prev
The number of requests to read the previous row in key order. This read method is mainly used to optimize ORDER BY ... DESC.
此选项表明在进行索引扫描时,按照索引倒序从数据文件里取数据的次数,一般就是ORDER BY ... DESC。
FLUSH STATUS;
SELECT col1 FROM foo ORDER BY col1 DESC;
mysql> SHOW SESSION STATUS LIKE 'Handle