2

我有一个超过 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 |
4

1 回答 1

1

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

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

MySQL 的基于成本的优化器认为,在第二次查询的情况下,最好使用“已尝试”的索引。

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

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

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

于 2012-06-19T13:57:23.050 回答