mysql索引的速度

时间:2011-12-09 19:24:26

标签: mysql performance indexing

我有一张平均约有2至5百万行的表格。它有一个名为'instruction_id'的主键/索引和另一个名为'mode'的索引字段。现在'instruction_id'当然是唯一的,因为它是主键,但'mode'只是3个不同值中的一个。我一直运行的查询是

SELECT * FROM tablename WHERE mode = 'value1' ORDER BY instruction_id LIMIT 50

目前这需要大约25秒(> 1秒是不可接受的长)但是现在只有600K行,因此随着表的增长它会变得更糟。以不同的方式索引会有帮助吗?如果我将instruction_id和mode一起索引会产生影响吗?如果我能以某种方式自然地通过instruction_id对表进行排序,那么我不需要通过另一种方式来询问订单,但我不知道如何做到这一点......任何帮助都会很棒。< / p>

4 个答案:

答案 0 :(得分:5)

你应该按顺序尝试索引(mode,instruction_id)。

该索引背后的原因是它创建了一个像这样的索引

mode  instruction_id
A     1
A     3
A     4
A     5
A     10
A     11
B     2
B     8
B     12
B     13
B     14
C     6
C     7
C     9
C     15
C     16
C     17

如果搜索模式B,sql server可以在模式下使用二进制搜索搜索索引,直到找到第一个B,然后它就可以简单地输出下一行n行。这将非常快,对于4M行大约22比较。

如果您希望订购结果,请始终使用ORDER BY,无论数据是如何存储的。查询引擎可能会选择一个查询计划,该计划以不同于PK顺序的顺序输出行(可能不是这样的简单情况,但一般情况下)。

答案 1 :(得分:3)

您应该查看以下与innodb聚集索引相关的链接

然后按照以下方式构建您的架构:

drop table if exists instruction_modes;
create table instruction_modes
(
mode_id smallint unsigned not null,
instruction_id int unsigned not null,
primary key (mode_id, instruction_id), -- note the clustered composite PK order !
unique key (instruction_id)
)
engine = innodb;

Cold(mysql重启)运行时性能如下:

select count(*) from instruction_modes;
+----------+
| count(*) |
+----------+
|  6000000 |
+----------+
1 row in set (2.54 sec)

select distinct mode_id from instruction_modes;
+---------+
| mode_id |
+---------+
|       1 |
|       2 |
|       3 |
+---------+
3 rows in set (0.06 sec)

select * from instruction_modes where mode_id = 2 order by instruction_id limit 10;
+---------+----------------+
| mode_id | instruction_id |
+---------+----------------+
|       2 |              2 |
|       2 |              3 |
|       2 |              4 |
|       2 |              5 |
|       2 |              6 |
|       2 |              9 |
|       2 |             14 |
|       2 |             25 |
|       2 |             28 |
|       2 |             32 |
+---------+----------------+
10 rows in set (0.04 sec)

0.04秒冷看起来非常高效。

希望这会有所帮助:)

答案 2 :(得分:2)

以下是一种可能的解决方案:

ALTER TABLE `tablename` ADD UNIQUE  (`mode`, instruction_id);

然后:

SELECT A.* FROM tablename A JOIN (
     SELECT instruction_id FROM tablename 
     WHERE mode = 'value1' 
     ORDER BY instruction_id LIMIT 50
     ) B 
ON (A.instruction_id = B.instruction_id);

我发现对于大型表,这种方法似乎对速度有效,因为子查询应该只使用索引。

我在一个包含&gt; 100mil记录的表上使用类似的查询,并在1-2秒内返回结果。

答案 3 :(得分:1)

'mode'是一个字符字段吗?如果它只能保存3个可能的值,听起来你应该把它变成一个枚举字段,它仍然会返回文本字符串但在内部存储为数字。

您还应该遵循Albin关于索引的建议,这将使您受益更多。