我有一张平均约有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>
答案 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关于索引的建议,这将使您受益更多。