在3.5亿条记录表中,结构为:
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 :(得分:1)
lock
被声明为NULLable
。这是否意味着该值通常为NULL
?如果是这样,那么MyISAM(不是InnoDB)中存在一个令人讨厌的问题,可能导致额外的500个碎片命中。
当更新MyISAM行和时,它变得更长,那么该行将不再适合它。 (现在我的详细知识变得模糊。)新行将放在其他地方和/或它将分成两部分,部分之间有链接。这意味着在两个地方写作。
正如Gordon指出的那样,对你的案例中任何索引列lock
的任何更改都涉及一个代价高昂的索引更新 - 从索引的BTree中的一个地方删除一行'并在另一个地方添加一行
lock
只有0或1的值吗?然后使用TINYINT
(1个字节),而不是MEDIUMINT
(3个字节)。
您应该检查MAX(id)
。如果它是干净的,id的最大值将是大约350M(不太接近4B的限制)。但如果有任何流失,可能会更接近极限。
我也主张转换到InnoDB。但是,您的10GB(数据+索引)将在转换中增长到20-30GB。
你是“锁定最老的解锁”东西吗?然后你会选择看看锁定了什么吗?
如果这个太慢,请不要一次做500,选择较低的数字。
使用InnoDB,你能避免锁定吗? 也许事务锁定就足够了?
我认为我们需要看到其他环境 - 其他表格,工作“流程”等。我们可能会提出其他建议。
我为INDEX(lock, time)
提出动议。但是,在执行此操作时,DROP
仅lock
上的索引是多余的。
转换为InnoDB时,请在同一 ALTER
中对所有索引进行更改。这比单独的传球跑得快。
答案 1 :(得分:0)
对于此查询:
UPDATE `table`
SET `lock` = 1
WHERE `lock` = 0
ORDER BY `time` ASC
LIMIT 500;
最佳指数为table(lock, time)
。但请注意,更新还需要更新索引,因此您应该测试它在实践中的效果。不要将其作为聚集索引。这只会减慢这个过程。