2012-06-15 54 views
4

我有一个超过900万行的非常大的表,在我的软件中,我需要快速在循环中选择查询。问题是查询需要将近4秒才能完成。下面是查询之一(他们是在所有相似,它们都具有相同的WHERE子句是减缓下来。MySQL如何加快此SELECT查询?

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

我使用的尝试列的布尔值是1或0下面是从查询的解释:

--------+--------------------------+ 
| 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) 

我需要大幅降低了查询时间。任何帮助是极大的赞赏。

+0

你可以发布'EXPLAIN SELECT'的输出吗?你知道有多少比例的'try = 0'和'tried = 1'吗? –

回答

6

您应该在(tried, id)上添加索引。

您已经在(username,id,tried)上添加了索引,但是由于tried不是索引中的第一项,因此该索引无法有效用于您所写的查询。


How MySQL Uses Indexes手册页:

MySQL使用索引这些操作:

  • 要查找特定的索引列key_colMIN()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;

请特别注意的是,WHERE条款必须是指发生之前列要为其计算MINMAX,这就是为什么当前的指数不能有效地使用列。


我需要快速做在一个循环中选择查询就可以了

你确定你需要在一个循环来查询?您是否考虑将循环移入数据库?也许你真正需要的是一个加入?最好发送一个查询获取大量数据的查询,而不是大量只能获取少量数据的小型查询。

+0

我刚添加show index的输出到我的文章。你可以看看有什么看起来不对吗?另外,你建议创建第二个复合索引吗? – xendi

+0

是索引是改进和加快mysql qureies操作的最佳选择。 – vimal

+0

@xendi:你没有说别的索引是什么。 –

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;

0

如果在tried列上添加索引,则查询速度应加快。

您可以使用如下命令

create index tried_ix1 on 04c1Tg0M (tried); 

作为一个侧面说明,如果你是在一个InnoDB表应用索引,也请考虑这个指标是否不应当被群集。例如,如果您要访问大量表记录,可能是按照特定顺序(可能是按顺序排列),那么可以考虑根据报告的排序要求创建聚集索引。