innodb index stats inadequate using constant innodb_stats_sample_pages
Affects | Status | Importance | Assigned to | Milestone | ||
---|---|---|---|---|---|---|
MySQL Server |
Unknown
|
Unknown
|
||||
Percona Server moved to https://jira.percona.com/projects/PS | Status tracked in 5.7 | |||||
5.5 |
Triaged
|
Medium
|
Unassigned | |||
5.6 |
Triaged
|
Medium
|
Unassigned | |||
5.7 |
Triaged
|
Medium
|
Unassigned |
Bug Description
If you set the number of analyzed pages to very low number compared to actual pages on that table/index it randomly pics those pages (default 8 pages), this leads to fact that query after analyze table returns different results. If the index tree is small, smaller than 10 * n_sample_pages + total_external_
How to repeat:
{noformat}
drop table if exists obs_daily;
CREATE TABLE `obs_daily` ( `iId` int(11) NOT NULL AUTO_INCREMENT, `sLocType` varchar(10) NOT NULL DEFAULT '', `sLocCode` varchar(30) NOT NULL DEFAULT '', `dtDate` date NOT NULL DEFAULT '0000-00-00', PRIMARY KEY (`iId`), UNIQUE KEY `idx_obs_daily_1` (`sLocType`
insert into obs_daily values (null, 'A', 'c1', '2014-11-
insert into obs_daily select null, 'A', sLocCode, '2014-08-12' from obs_daily;
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
insert into obs_daily select null, 'A', concat(
select * from information_
set global innodb_
analyze table obs_daily;
select * from information_
analyze table obs_daily;
select * from information_
analyze table obs_daily;
select * from information_
{noformat}
Output can be following:
{noformat}
MariaDB [test]> select count(*) from obs_daily;
+----------+
| count(*) |
+----------+
| 1048576 |
+----------+
1 row in set (2.22 sec)
MariaDB [test]> select count(distinct sLocType) from obs_daily;
+------
| count(distinct sLocType) |
+------
| 1 |
+------
1 row in set (0.01 sec)
MariaDB [test]> select count(distinct sLocCode) from obs_daily;
+------
| count(distinct sLocCode) |
+------
| 1007624 |
+------
1 row in set (5.65 sec)
MariaDB [test]> select count(distinct dtDate) from obs_daily;
+------
| count(distinct dtDate) |
+------
| 15 |
+------
1 row in set (0.00 sec)
MariaDB [test]> set global innodb_
Query OK, 0 rows affected (0.00 sec)
MariaDB [test]> analyze table obs_daily;
+------
| Table | Op | Msg_type | Msg_text |
+------
| test.obs_daily | analyze | status | OK |
+------
1 row in set (0.02 sec)
MariaDB [test]> select * from information_
+------
| table_schema | table_name | index_name | fields | rows_per_key | index_total_pages | index_leaf_pages |
+------
| test | obs_daily | PRIMARY | 1 | 1 | 2852 | 2844 |
| test | obs_daily | idx_obs_daily_1 | 3 | 115183, 0, 0 | 3628 | 3138 |
| test | obs_daily | idx_obs_daily_2 | 2 | 115183, 0 | 865 | 814 |
+------
3 rows in set (0.00 sec)
MariaDB [test]> analyze table obs_daily;
+------
| Table | Op | Msg_type | Msg_text |
+------
| test.obs_daily | analyze | status | OK |
+------
1 row in set (0.02 sec)
MariaDB [test]> select * from information_
+------
| table_schema | table_name | index_name | fields | rows_per_key | index_total_pages | index_leaf_pages |
+------
| test | obs_daily | PRIMARY | 1 | 1 | 2852 | 2844 |
| test | obs_daily | idx_obs_daily_1 | 3 | 116842, 1, 0 | 3628 | 3138 |
| test | obs_daily | idx_obs_daily_2 | 2 | 116842, 0 | 865 | 814 |
+------
3 rows in set (0.00 sec)
MariaDB [test]> analyze table obs_daily;
+------
| Table | Op | Msg_type | Msg_text |
+------
| test.obs_daily | analyze | status | OK |
+------
1 row in set (0.02 sec)
MariaDB [test]> select * from information_
+------
| table_schema | table_name | index_name | fields | rows_per_key | index_total_pages | index_leaf_pages |
+------
| test | obs_daily | PRIMARY | 1 | 1 | 2852 | 2844 |
| test | obs_daily | idx_obs_daily_1 | 3 | 116407, 1, 1 | 3628 | 3138 |
| test | obs_daily | idx_obs_daily_2 | 2 | 116407, 0 | 865 | 814 |
+------
3 rows in set (0.00 sec)
{noformat}
See https:/
tags: | added: userstat |
So, this is essentially what's suggested in the patch (with new variables to control behavior and tests to check all these):
... sample_ pages and number of sample_ pages. */ >stat_index_ size > 0) { stat_index_ size; ut_min( srv_stats_ sample_ pages, index-> stat_index_ size), >stat_index_ size)*srv_ stats_sample_ pages);
+ /* New logaritmic number of pages that are estimated. We
+ first pick minimun from srv_stats_
+ pages on index. Then we pick maximum from previous number of
+ pages and log2(number of index pages) * srv_stats_
if (index-
- n_sample_pages = index->
+ n_sample_pages = ut_max(
+ log2(index-
} else {
n_sample_pages = 1;
...
This may surely work better than default setting or even any one picked by DBA based on some reasoning. So, I think we should consider this feature seriously (for 5.5 and for tables that do not use persistent statistics in 5.6).