為什么rows這么大,在mysql explain中---寫在去acumg聽講座的前一夜


這周五下班前,發現了一個奇怪問題,大概是這個背景

一張表,結構為

Create Table: CREATE TABLE `out_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=Innodb AUTO_INCREMENT=36865 DEFAULT CHARSET=latin1

總共有37K rows的數據,數據大概是這樣

+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |
|  3 | c    |
|  4 | D    |
|  5 | c    |
|  6 | c    |
|  7 | c    |
|  8 | c    |
|  9 | c    |
| 10 | a    |
+----+------+

運行了這個SQL

mysql> select id from out_table where id >10000  limit 1;
+-------+
| id    |
+-------+
| 10001 |
+-------+
1 row in set (0.00 sec)

速度也很快。

可是在運行explain的時候

mysql> explain select id from out_table where id >10000  limit 1;
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | out_table | range | PRIMARY       | PRIMARY | 4       | NULL | 26358 | Using where; Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+

發現rows居然有,26358

查看MySQL官方文檔,rows所代表的含義

Column Meaning
rows Estimate of rows to be examined

翻譯過來就是,估計需要檢測的行數。

可是從DBA的直覺來說,id字段為主鍵,且為自增屬性,另外后面有個limit 1,那么無論如何rows應該不大於1才對。

那么是否explain沒有考慮后面的limit 1呢?

繼續運行SQL驗證

mysql> explain select id from out_table where id >10000 ;
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | out_table | range | PRIMARY       | PRIMARY | 4       | NULL | 26358 | Using where; Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+

果然后面的limit 1根本不影響rows的值

那么這個rows是怎么算出來的呢?我們翻看下MySQL源碼(以5.6.23為例)。

為了避免不擅長的大段落描述,我把幾個關鍵的文件和函數粘貼出來。

 

文件 關鍵部分 下一步
sql/opt_explain_traditional.cc" push(&items, column_buffer.col_rows, nil) col_rows
sql/opt_explain.cc select->quick->records records
sql/opt_range.cc check_quick_select  

而check_quick_select的功能,在MySQL源碼中的注釋為

Calculate estimate of number records that will be retrieved by a range scan on given index using given SEL_ARG intervals tree.

翻譯過來就是,這個方法僅僅根據給出的關於這個索引的條件和索引本身,來判斷需要掃描多少行。顯然limit 1和這個索引是沒有直接關系的。

所以新姿勢,get!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM