MySQL 5.7.25 [innoDB],索引基数突然reset/change变回1
MySQL 5.7.25 [innoDB], index cardinality suddenly reset/change back to 1
我正在使用 MySql v 5.7.25 和 innoDB。
我有一个 table inventories
有 100 个 mio 数据
这是 SHOW CREATE TABLE inventories;
时的样子
注意:删除了不相关的字段。
CREATE TABLE `inventories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) DEFAULT NULL,
`quantity` decimal(50,6) DEFAULT NULL,
`line_number` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_inventories_on_line_number` (`line_number`),
KEY `idx_pr_ln` (`product_id`,`line_number`),
) ENGINE=InnoDB AUTO_INCREMENT=39905 DEFAULT CHARSET=latin1
问题是索引 idx_pr_ln
上的索引基数突然在字段 line_number 上重置为 1。
mysql > show index from inventories;
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
|-------------|------------|---------------------------------------|--------------|-------------|-----------|-------------|----------|--------|------|------------|---------|---------------|
| inventories | 1 | index_inventories_on_line_number | 1 | line_number | A | 3025563 | | | YES | BTREE | | |
| inventories | 1 | idx_pr_ln | 1 | product_id | A | 4337902 | | | YES | BTREE | | |
| inventories | 1 | idx_pr_ln | 2 | line_number | A | 1 | | | YES | BTREE | | |
每个使用索引 idx_pr_ln
的 SELECT
查询现在都进行 FULL table 扫描,因为 line_number.
上的基数 1
在我执行 ANALYZE TABLE inventories
后,它会回到 'correct' 值大约 100 mio。
但是过几天又出现了(又重新设置为1)
我的问题是
为什么这个基数突然 reset/change 到 1?
你们有没有遇到过这种情况?
这是 MySql 上的错误吗?
如有任何解释/建议,我们将不胜感激。
谢谢。
注意:table 或索引没有变化,
没有改变 table,没有添加/删除索引。
只有可能改变的数据 (CUD)
编辑:
select 语句是这样的
SELECT product_id, line_number FROM inventories WHERE product_id = 123 AND line_number < 321
SHOW INDEXES
中的 1 完全正常。它们不表示当前值。
"index_inventories_on_line_number" 有一列,序号 1 of 1
"idx_pr_ln" 有 2 列,编号为 1 和 2。
第二个索引的两列的"cardinality"是第一列的“4337902”,也就是说有"a lot of different values"。对于其中的每一个,第二列都是唯一的或接近唯一的(“1”)。
MySQL/InnoDB 绝不会操纵除 PRIMARY KEY
列以外的任何其他列的值,即 id
。它会递增,除了 TRUNCATE TABLE
会重置它。
every SELECT query that use index idx_pr_ln now do FULL table scan because of cardinality 1 on line_number.
视情况而定。
对于 SELECT ... WHERE line_number = 432
,是的,它将进行完整的 table 扫描。这是因为line_number
在复合索引中不是第一个。
对于SELECT ... WHERE product_id = 987
,它将使用索引。
如需进一步讨论,请提供示例 SELECTs
。
cardinality on index idx_pr_ln suddenly reset to 1 on field line_number
InnoDB 将进行一些随机探测以确定列的统计信息(基数)。如果碰巧看到 line_number
的唯一值,则基数设置为 1。如果没有,则使用某个更大的值。
统计信息用于决定优化查询。让我们看看一个 运行 比您认为应该慢的查询。 那 是我们应该关注的地方。
我发现了问题所在,导致索引基数为 1。
如@Rick James 所述
InnoDB will make a few random probes to determine statistics (cardinality) of columns. If it happens to see unique values for line_number, then the cardinality is set to 1. If not, some larger value is used.
在阅读了这篇 mysql 文档之后
https://dev.mysql.com/doc/refman/5.7/en/innodb-persistent-stats.html
这是由于 mysql 的统计更新造成的,当时有 10% 的数据(在本例中大约为 10 mio)发生了变化。
STATS_AUTO_RECALC specifies whether to automatically recalculate persistent statistics. The value DEFAULT causes the persistent statistics setting for the table to be determined by the innodb_stats_auto_recalc setting. A value of 1 causes statistics to be recalculated when 10% of table data has changed. A value 0 prevents automatic recalculation for the table. When using a value of 0, use ANALYZE TABLE to recalculate statistics after making substantial changes to the table.
STATS_SAMPLE_PAGES specifies the number of index pages to sample when cardinality and other statistics are calculated for an indexed column, by an ANALYZE TABLE operation
使用默认设置 STATS_AUTO_RECALC=1 和 STATS_SAMPLE_PAGES=20,mysql 有可能扫描包含不同值的示例页面(20 上只有 1 个不同值页样本)。
我更新后 STATS_SAMPLE_PAGES=30,它不太可能有基数 1。
我正在使用 MySql v 5.7.25 和 innoDB。
我有一个 table inventories
有 100 个 mio 数据
这是 SHOW CREATE TABLE inventories;
注意:删除了不相关的字段。
CREATE TABLE `inventories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) DEFAULT NULL,
`quantity` decimal(50,6) DEFAULT NULL,
`line_number` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_inventories_on_line_number` (`line_number`),
KEY `idx_pr_ln` (`product_id`,`line_number`),
) ENGINE=InnoDB AUTO_INCREMENT=39905 DEFAULT CHARSET=latin1
问题是索引 idx_pr_ln
上的索引基数突然在字段 line_number 上重置为 1。
mysql > show index from inventories;
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
|-------------|------------|---------------------------------------|--------------|-------------|-----------|-------------|----------|--------|------|------------|---------|---------------|
| inventories | 1 | index_inventories_on_line_number | 1 | line_number | A | 3025563 | | | YES | BTREE | | |
| inventories | 1 | idx_pr_ln | 1 | product_id | A | 4337902 | | | YES | BTREE | | |
| inventories | 1 | idx_pr_ln | 2 | line_number | A | 1 | | | YES | BTREE | | |
每个使用索引 idx_pr_ln
的 SELECT
查询现在都进行 FULL table 扫描,因为 line_number.
在我执行 ANALYZE TABLE inventories
后,它会回到 'correct' 值大约 100 mio。
但是过几天又出现了(又重新设置为1)
我的问题是
为什么这个基数突然 reset/change 到 1?
你们有没有遇到过这种情况?
这是 MySql 上的错误吗?
如有任何解释/建议,我们将不胜感激。 谢谢。
注意:table 或索引没有变化, 没有改变 table,没有添加/删除索引。 只有可能改变的数据 (CUD)
编辑: select 语句是这样的
SELECT product_id, line_number FROM inventories WHERE product_id = 123 AND line_number < 321
SHOW INDEXES
中的 1 完全正常。它们不表示当前值。
"index_inventories_on_line_number" 有一列,序号 1 of 1
"idx_pr_ln" 有 2 列,编号为 1 和 2。
第二个索引的两列的"cardinality"是第一列的“4337902”,也就是说有"a lot of different values"。对于其中的每一个,第二列都是唯一的或接近唯一的(“1”)。
MySQL/InnoDB 绝不会操纵除 PRIMARY KEY
列以外的任何其他列的值,即 id
。它会递增,除了 TRUNCATE TABLE
会重置它。
every SELECT query that use index idx_pr_ln now do FULL table scan because of cardinality 1 on line_number.
视情况而定。
对于 SELECT ... WHERE line_number = 432
,是的,它将进行完整的 table 扫描。这是因为line_number
在复合索引中不是第一个。
对于SELECT ... WHERE product_id = 987
,它将使用索引。
如需进一步讨论,请提供示例 SELECTs
。
cardinality on index idx_pr_ln suddenly reset to 1 on field line_number
InnoDB 将进行一些随机探测以确定列的统计信息(基数)。如果碰巧看到 line_number
的唯一值,则基数设置为 1。如果没有,则使用某个更大的值。
统计信息用于决定优化查询。让我们看看一个 运行 比您认为应该慢的查询。 那 是我们应该关注的地方。
我发现了问题所在,导致索引基数为 1。
如@Rick James 所述
InnoDB will make a few random probes to determine statistics (cardinality) of columns. If it happens to see unique values for line_number, then the cardinality is set to 1. If not, some larger value is used.
在阅读了这篇 mysql 文档之后 https://dev.mysql.com/doc/refman/5.7/en/innodb-persistent-stats.html
这是由于 mysql 的统计更新造成的,当时有 10% 的数据(在本例中大约为 10 mio)发生了变化。
STATS_AUTO_RECALC specifies whether to automatically recalculate persistent statistics. The value DEFAULT causes the persistent statistics setting for the table to be determined by the innodb_stats_auto_recalc setting. A value of 1 causes statistics to be recalculated when 10% of table data has changed. A value 0 prevents automatic recalculation for the table. When using a value of 0, use ANALYZE TABLE to recalculate statistics after making substantial changes to the table.
STATS_SAMPLE_PAGES specifies the number of index pages to sample when cardinality and other statistics are calculated for an indexed column, by an ANALYZE TABLE operation
使用默认设置 STATS_AUTO_RECALC=1 和 STATS_SAMPLE_PAGES=20,mysql 有可能扫描包含不同值的示例页面(20 上只有 1 个不同值页样本)。
我更新后 STATS_SAMPLE_PAGES=30,它不太可能有基数 1。