4

我有一个超过 900 万行的非常大的表,在我的软件中,我需要在循环中快速对其进行选择查询。问题是查询需要将近 4 秒才能完成。这是其中一个查询(它们都是相似的,因为它们都有相同的 WHERE 子句,这会减慢它们的速度:

SELECT MIN(id)
FROM `04c1Tg0M`
WHERE `tried` = 0;

我将尝试过的列用作布尔值。该值为 1 或 0。这是该查询的 EXPLAIN:

--------+--------------------------+
| id | select_type | table    | type  | possible_keys | key  | key_len | ref  | rows    | Extra                    |
+----+-------------+----------+-------+---------------+------+---------+------+---------+--------------------------+
|  1 | SIMPLE      | 04c1Tg0M | index | NULL          | pdex | 158     | NULL | 9275107 | Using where; Using index |
+----+-------------+----------+-------+---------------+------+---------+------+---------+--------------------------+

这是表结构:

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`)
) ENGINE=MyISAM AUTO_INCREMENT=9275108 DEFAULT CHARSET=utf8

这是显示索引的输出:

| 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         |     9275107 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            1 | username    | A         |     9275107 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            2 | id          | A         |     9275107 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            3 | tried       | A         |     9275107 |     NULL | NULL   | YES  | BTREE      |         |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

这是相关查询的输出:

+---------+
| MIN(id) |
+---------+
|       1 |
+---------+
1 row in set (3.76 sec)

我需要大幅减少查询时间。任何帮助是极大的赞赏。

4

3 回答 3

6

您应该在(tried, id).

您已经添加了一个索引,(username,id,tried)但是该索引不能有效地用于您编写的查询,因为该字段tried不是索引中的第一项。


从手册页如何 MySQL 使用索引

MySQL 对这些操作使用索引:

  • 查找特定索引列的MIN()或值。这由预处理器优化,该预处理器检查您是否正在使用索引中之前出现的所有关键部分。在这种情况下,MySQL 为每个or表达式执行单个键查找并将其替换为常量。如果所有表达式都替换为常量,则查询立即返回。例如:MAX()key_colWHERE key_part_N = constantkey_colMIN()MAX()

    SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;

请特别注意,该WHERE子句必须引用出现在您希望计算or的列之前的列,这就是您当前索引没有有效使用的原因。MINMAX


我需要在循环中快速对其进行选择查询

您确定需要循环查询吗?您是否考虑过将循环移入数据库?也许您真正需要的是加入?发送一个获取大量数据的单个查询比发送许多只获取少量数据的小查询要好。

于 2012-06-15T17:15:12.730 回答
2

在列上添加索引tried应该可以加快查询速度。MySQL 对这些操作使用索引:

查找特定索引列 key_col 的 MIN() 或 MAX() 值。这是由预处理器优化的,该预处理器检查您是否在索引中 key_col 之前出现的所有关键部分上使用 WHERE key_part_N = constant。在这种情况下,MySQL 为每个 MIN() 或 MAX() 表达式执行单个键查找,并将其替换为常量。如果所有表达式都替换为常量,则查询立即返回。例如:

SELECT MIN(key_part2),MAX(key_part2) FROM tbl_name WHERE key_part1=10;

于 2012-06-15T17:18:39.300 回答
0

如果您在tried列上添加索引,您的查询应该会加快。

您可以使用类似的命令

create index tried_ix1 on 04c1Tg0M (tried);

附带说明一下,如果您在 InnoDb 表上应用索引,还请考虑是否应该聚集该索引。例如,如果您要以特定的(可能已排序的)顺序访问大量表记录,可能是一个报告,那么请考虑根据该报告的排序要求创建一个聚集索引。

于 2012-06-16T10:50:38.633 回答