【问题标题】:MySQL Inconsistencies in index usage on the same queryMySQL 在同一查询上的索引使用不一致
【发布时间】:2012-06-15 20:11:45
【问题描述】:

我有一个超过 900 万行的表。我有一个使用索引的 SELECT 查询。这是查询:

SELECT `username`,`id`
FROM `04c1Tg0M`
WHERE `id` > 9259466
AND `tried` = 0
LIMIT 1;

该查询执行得非常快(0.00 秒)。以下是该查询的解释:

+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+
| id | select_type | table    | type  | possible_keys   | key     | key_len | ref  | rows  | Extra       |
+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+
|  1 | SIMPLE      | 04c1Tg0M | range | PRIMARY,triedex | PRIMARY | 4       | NULL | 10822 | Using where |
+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+

现在这里是相同的查询,只是我要将 id 更改为 6259466:

SELECT `username`,`id`
FROM `04c1Tg0M`
WHERE `id` > 5986551
AND `tried` = 0
LIMIT 1;

该查询需要 4.78 秒才能完成。这就是问题。以下是该查询的解释:

+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+
| id | select_type | table    | type | possible_keys   | key     | key_len | ref   | rows    | Extra       |
+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+
|  1 | SIMPLE      | 04c1Tg0M | ref  | PRIMARY,triedex | triedex | 2       | const | 9275107 | Using where |
+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+

这里发生了什么,我该如何解决?这是我的索引:

+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| 04c1Tg0M |          0 | PRIMARY  |            1 | id          | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            1 | username    | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            2 | id          | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            3 | tried       | A         |     9275093 |     NULL | NULL   | YES  | BTREE      |         |
| 04c1Tg0M |          1 | triedex  |            1 | tried       | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |
| 04c1Tg0M |          1 | triedex  |            2 | id          | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

这是我的表结构:

| 04c1Tg0M | CREATE TABLE `04c1Tg0M` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`tried` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `pdex` (`username`,`id`,`tried`),
KEY `triedex` (`tried`,`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9275108 DEFAULT CHARSET=utf8 |

【问题讨论】:

  • 您是否一个接一个地运行这些查询?
  • 相隔几秒
  • 您是否意识到您检查的行数比第一个查询多 3M 行(假设 ID 是相关的)?结果中只得到一行,但要检查更多行。
  • @Ander2 这可能是因为它没有使用索引。 NO index = 必须检查更多记录才能找到正确的记录。这称为全表扫描。
  • 表中不超过9275108条记录,所以id > 9259466不必检查很多索引值。当更改为id > 5986551 时,它必须查看更多值(可能是大多数值)。因此,我认为优化器认为在tried 上使用索引将比在id 上使用索引更具限制性,因此它使用它来代替。

标签: mysql indexing


【解决方案1】:

第一个SQL返回10822行,第二个返回9275107行!

在第二个查询中使用主键“id”索引并不是很有用,因为无论如何您都必须进行全表扫描。

MySQL 的基于成本的优化器认为,在第二次查询的情况下,最好使用 'tried' 上的索引。

如果您必须进行全表扫描,最好不要使用索引,因为索引会构成额外的磁盘读取。

您可以在查询中使用“使用索引”或“强制索引”来提示优化器是否使用索引。

还可以通过定期分析您的表来更新统计信息,以便基于成本的优化器正常工作。

【讨论】:

  • 强制索引或索引提示肯定会起作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-10
  • 2015-08-30
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多