2017-04-22 109 views
0

在350万条记录的表,其结构是:哪个索引会加快查询速度?

CREATE TABLE `table` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `job_id` int(10) unsigned NOT NULL, 
    `lock` mediumint(6) unsigned DEFAULT '0', 
    `time` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `job_id` (`job_id`), 
    KEY `lock` (`lock`), 
    KEY `time` (`time`) 
) ENGINE=MyISAM; 

我应该创建什么索引来加快查询:

UPDATE `table` SET `lock` = 1 WHERE `lock` = 0 ORDER BY `time` ASC LIMIT 500; 
+0

为什么使用MyISAM?如果你经常运行这个查询,MyISAM只有一个表锁。这意味着当这个查询(或其他一些写入)运行其他人可以读取或写入这个表 –

+0

@BerndBuffen,你建议使用什么? – Dmitry

+0

请不要使用不相关的数据库标签。 –

回答

0

对于此查询:

UPDATE `table` 
    SET `lock` = 1 
    WHERE `lock` = 0 
    ORDER BY `time` ASC 
    LIMIT 500; 

最好的指数是table(lock, time)。但请注意,更新还需要更新索引,因此您应该测试它在实际中的工作情况。不要把它作为聚集索引。这只会减缓这一进程。

+0

这个密钥的工作时间很长。这似乎是由于请求导致更新相同索引的事实。 – Dmitry

1

lock被宣布为NULLable。这是否意味着价值往往是NULL?如果是这样,那么在MyISAM(而不是InnoDB)中存在一个令人讨厌的问题,可能会导致500次额外的碎片命中。

当MyISAM行更新它变得更长,那么该行将不再适合它的位置。 (现在我的详细知识变得模糊了。)新的行将被放置在其他地方,并且/或者它将被分成两部分,并且部分之间有链接。这意味着写在两个地方。

戈登指出,任何改变你的情况下,任何索引列,lock,涉及昂贵的索引更新 - 从一个地方索引的B树中删除“行”,并在另一个地方添加一行。

lock只有值0或1?然后使用TINYINT(1字节),而不是MEDIUMINT(3字节)。您需要检查MAX(id)。如果它是干净的,id的最大值将是大约350M(不太接近4B的限制)。但如果有任何流失,它可能会更接近极限。

我也提倡切换到InnoDB。但是,您的10GB(数据+索引)在转换中将增长到20-30GB。

你是否“锁定最古老的解锁”thingies?你会做一个选择,看看什么被锁定?

如果这太慢,一次不要做500,选择一个较低的数字。

有了InnoDB,你可以避免锁定吗? 也许事务锁定就足够了?

我认为我们需要看看环境的其他部分 - 其他表格,工作“流动”等。我们可能会提出其他建议。

而我第二个动议为INDEX(lock, time)。但是这样做的时候,DROP这个索引就是lock那样多余。

而当转换为InnoDB时,请在同一个ALTER中执行所有索引更改。这将比单独的传球跑得快。

+0

感谢您的回答,我尝试将表转移到InnoDB并执行sql查询的测试。 – Dmitry