大家。这是我的 mysql 服务器出现的问题。
我有一个大约 40,000,000 行和 10 列的表。
大小约为4GB,引擎为innodb。
它是一个主数据库,这样只执行一条sql。
insert into mytable ... on duplicate key update ...
大约 99% 的 sql 执行了 update
部分。
现在服务器变得越来越慢。 我听说分割表可以提高它的性能。然后我在我的个人电脑上尝试,分成10个表,失败,也尝试了100个,也失败。速度反而变慢了。所以我想知道为什么拆分表没有提高性能?
提前致谢。
更多详细信息:
CREATE TABLE my_table (
id BIGINT AUTO_INCREMENT,
user_id BIGINT,
identifier VARCHAR(64),
account_id VARCHAR(64),
top_speed INT UNSIGNED NOT NULL,
total_chars INT UNSIGNED NOT NULL,
total_time INT UNSIGNED NOT NULL,
keystrokes INT UNSIGNED NOT NULL,
avg_speed INT UNSIGNED NOT NULL,
country_code VARCHAR(16),
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(id), UNIQUE KEY(user_id)
);
PS:
我还尝试了带有固态驱动器和硬盘驱动器的不同计算机,但也没有帮助。
最佳答案
拆分表格根本不可能有帮助。 分区
也是如此。
让我们计算一下磁盘点击次数。我将跳过计算 BTree 中的非叶节点;它们往往会被缓存;我会统计数据和索引中的叶节点;它们往往不会被缓存。
IODKU 的作用是:
- 读取包含任何
UNIQUE
键的索引 block 。就您而言,这可能是user_id
。请提供示例 SQL 语句。 1 读。 - 如果在索引中找到
user_id
条目,则从 PK(id
) 索引的数据中读取记录并执行UPDATE
,并将第二个 block 保留在 buffer_pool 中,以便最终重写到磁盘。 1 现在阅读,1 稍后写入。 - 如果未找到记录,请执行
INSERT
。需要新行的索引 block 已被读取,因此已准备好插入新条目。同时,表中的“最后一个” block (由于id
为AUTO_INCRMENT
)可能已被缓存。将新行添加到其中。 0 现在读取,1 稍后写入(UNIQUE
)。 (重写“最后” block 会分摊到 100 行,所以我忽略它。) - 最终进行写入。
总计,假设基本上全部采用 UPDATE
路径:2 次读取和 1 次写入。假设 user_id
不遵循简单的模式,我将假设所有 3 个 I/O 都是“随机”的。
让我们考虑一个变体...如果去掉 id
会怎样?您在其他地方还需要 id
吗?由于您有一个 UNIQUE
key ,它可能是 PK。即将两个索引替换为 PRIMARY KEY(user_id)
。现在计数是:
- 已阅读 1 次
- 如果
更新
,0 次读取,1 次写入 - 如果
INSERT
,0 次读取,0 次写入
总计:1 次读取,1 次写入。是以前的 2/3。更好了,但仍然不是很好。
缓存
你有多少内存?
innodb_buffer_pool_size
的值是多少?
显示表状态
-- 什么是Data_length
和Index_length
?
我怀疑buffer_pool不够大,可能可以提高。如果您的 RAM 超过 4GB,请将其设置为 RAM 的 70% 左右。
其他
SSD 应该有很大帮助,因为您似乎受到 I/O 限制。您能区分出您是 I/O 密集型还是 CPU 密集型吗?
您一次更新多少行?多久时间?是批量的还是一次一个?这里可能会有显着的改进。
你真的需要BIGINT
(8字节)吗? INT UNSIGNED
只有 4 个字节。
是否涉及交易?
主人有问题吗?奴隶?两个都?我不想以弄乱从站的方式修复主站。
关于mysql - mysql中的分表性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42218593/