我试图用我们的数据库服务器诊断看似随机的性能问题。下面是一个简化的场景,希望足够通用,可以作为任何寻找相同答案的人的有用的未来参考。
假设我有一个(MySQL 5.6 w/ InnoDB)表
CREATE TABLE Example (
id INT NOT NULL AUTO_INCREMENT,
secondary_id INT DEFAULT NULL,
some_data TEXT NOT NULL,
PRIMARY KEY (id),
KEY (secondary_id)
) ENGINE=InnoDB;
Run Code Online (Sandbox Code Playgroud)
大约有 1500 万行。但是,该secondary_id列NULL几乎适用于所有行,因此索引的secondary_id基数非常非常低(在我们的示例中约为 30k)。在我们的例子中,当我们遇到我正在调查的性能问题时,服务器的进程列表显示了许多(100+)个表单查询:
UPDATE Example SET secondary_id = NULL, some_data = '...' WHERE id = 123;
Run Code Online (Sandbox Code Playgroud)
需要大约 90+ 秒才能完成,在此期间它们处于“更新”状态。(这些查询将在单独的事务中运行。)
我特别想知道从非空secondary_id到空的转换secondary_id是否会导致上述UPDATE. 也就是说,在这种情况下更新索引是否可能需要大量时间,因为有这么多行(约 1500 万)对该列 ( NULL)具有相同的值?
我想这个问题源于我不理解 B+Tree 索引如何为具有重复索引值的行存储行指针。我猜这个节点会有一个插入时间非常快的链表(或类似的东西),所以我猜我的问题的答案是“否”。但我想向专家们,即你们所有人,确认这一点。
我试图在这里做大量的研究,但我两手空空。可能最全面的帖子是this one,它解释了一些处理重复键的不同技术,但我特别在寻找InnoDB/MySQL的方法。