web-dev-qa-db-ja.com

EXPLAINの行が正確でないのはなぜですか?

私は次の表を持っています:

mysql> select count(*) from employees;  
+----------+  
| count(*) |  
+----------+  
|    10000 |  
+----------+  
1 row in set (0.03 sec)  

EXPLAIN:mysql> Explain select last_name from employee order by last_name;

+----+-------------+-----------+------+---------------+------+---------+------+------+----------------+  
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-----------+------+---------------+------+---------+------+------+----------------+  
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 9894 | Using filesort |  
+----+-------------+-----------+------+---------------+------+---------+------+------+----------------+  
1 row in set (0.00 sec)

行は9894です。私は10000を期待していました。
私がやります:

mysql> analyze table employees;
+-------------------------------------+---------+----------+----------+  
| Table                               | Op      | Msg_type | Msg_text |  
+-------------------------------------+---------+----------+----------+  
| sql_dummy.employees | analyze | status   | OK       |  
+-------------------------------------+---------+----------+----------+  
1 row in set (0.04 sec)  

EXPLAINを再実行します:

mysql> Explain select last_name from employee order by last_name;

+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows  | Extra          |  
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 10031 | Using filesort |  
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
1 row in set (0.01 sec)  

行は10031になりました。

行が10000にならない理由を誰かが知っていますか?私は他の場合にもこれに気づきました。

2
Cratylus

これは驚くべきことかもしれませんが、それがInnoDBの動作です。

InnoDBストレージエンジンは、リーフ以外のBTREEノードを数レベル下に移動することでカーディナリティの近似を行い、知識に基づいた推測を行います。

私はこれについてずっと前に mysqlperformanceblog.com に基づいて書いた

おそらく、これを実行してその動作を無効にしてみることができます:

SET GLOBAL innodb_stats_on_metadata = 0;

innodb_stats_on_metadata を設定すると、おおよそのカーディナリティが安定し、同じカーディナリティが何度も得られるはずです。

2
RolandoMySQLDBA