私は次の表を持っています:
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にならない理由を誰かが知っていますか?私は他の場合にもこれに気づきました。
これは驚くべきことかもしれませんが、それがInnoDBの動作です。
InnoDBストレージエンジンは、リーフ以外のBTREEノードを数レベル下に移動することでカーディナリティの近似を行い、知識に基づいた推測を行います。
私はこれについてずっと前に mysqlperformanceblog.com に基づいて書いた
Jun 21, 2011
: MySQLクエリオプティマイザはどこからインデックス統計を読み取りますか?Aug 03, 2011
: いつインデックスを再構築する必要がありますか?Feb 23, 2013
: mysqlはmyisamおよびinnodbテーブルにアクセスするクエリをどのように処理しますか?おそらく、これを実行してその動作を無効にしてみることができます:
SET GLOBAL innodb_stats_on_metadata = 0;
innodb_stats_on_metadata を設定すると、おおよそのカーディナリティが安定し、同じカーディナリティが何度も得られるはずです。