Rei*_*eid 5 mysql innodb index btree
我试图用我们的数据库服务器诊断看似随机的性能问题。下面是一个简化的场景,希望足够通用,可以作为任何寻找相同答案的人的有用的未来参考。
假设我有一个(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的方法。
单曲90秒UPDATE听起来也太多了。可能涉及一些阻塞,应该进行调查。
除此之外,拥有 98% 相同 ( NULL) 值的列听起来也不好。您应该考虑将该列放在一个单独的表中(该表只有 30K 行)。这会让你的INSERT/DELETE/UPDATE程序变得有点复杂,但你可能会从较小的索引中获益。建议设计:
CREATE TABLE Example (
id INT NOT NULL AUTO_INCREMENT,
some_data TEXT NOT NULL,
PRIMARY KEY (id)
) ENGINE = InnoDB ;
CREATE TABLE Example_secondary (
id INT NOT NULL,
secondary_id INT NOT NULL,
PRIMARY KEY (id),
INDEX (secondary_id),
FOREIGN KEY (id)
REFERENCES Example (id)
) ENGINE = InnoDB ;
Run Code Online (Sandbox Code Playgroud)
然后你的UPDATE:
UPDATE Example
SET secondary_id = NULL,
some_data = '...'
WHERE id = 123 ;
Run Code Online (Sandbox Code Playgroud)
会成为:
BEGIN ;
UPDATE Example
SET some_data = '...'
WHERE id = 123 ;
DELETE FROM Example_secondary
WHERE id = 123 ;
COMMIT ;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
623 次 |
| 最近记录: |