MySQL UPDATES逐渐变慢

时间:2016-06-25 07:56:03

标签: mysql database

我有一个应用程序使用托管在一台计算机上的MySQL数据库和在其他计算机上运行的6个客户端,这些计算机通过本地网络读取和写入。

我有一个主要的工作表,其中包含大约120,000个要处理的行。每个客户端从表中抓取40个未分配的工作项(将它们标记为已分配),完成工作,然后将结果写回到同一工作表中。这个序列一直持续到没有更多的工作要做。

enter image description here

以上是一张图片,显示了使用UPDATE查询从其中一个客户端向表中写回40个结果的每个块所花费的时间。您可以看到持续时间在大多数时间内相当小,但突然持续时间达到300秒并保持在那里直到所有工作完成。这种快速增加的时间来执行查询是我需要帮助的。

客户端负载不重。服务器有点装,但它有16GB的RAM,8个核心,除了托管这个数据库之外什么也没做。

这是相关的SQL代码。

创建表:

CREATE TABLE work (
     item_id MEDIUMINT,
     item VARCHAR(255) CHARACTER SET utf8,
     allocated_node VARCHAR(50),
     allocated_time DATETIME,
     result TEXT);
/* Then insert 120,000 items, which is quite fast. No problem at this point. */
INSERT INTO work VALUES (%s,%s,%s,NULL,NULL,NULL);

客户分配40个项目:

UPDATE work SET allocated_node = %s, allocated_time=NOW()
       WHERE allocated_node IS NULL LIMIT 40;
SELECT item FROM work WHERE allocated_node = %s AND result IS NULL;

使用完成的结果更新行(这是在运行几个小时后变得非常慢的部分):

/* The chart above shows the time to execute 40 of these for each write back of results */
UPDATE work SET result = %s WHERE item = %s;

我在Ubuntu 14.04上使用MySQL,具有所有标准设置。 决赛桌大约160MB,没有索引。

我没有看到我的查询有任何问题,除了整个事情需要两倍的时间之外,它们的工作正常。

具有这些问题经验的人是否可以建议我在MySQL中更改任何配置设置以修复此性能问题,或者请指出我正在做的任何可能解释图表中时间的问题。

感谢。

3 个答案:

答案 0 :(得分:0)

如果没有索引,则会扫描整个表格。如果项ID越大,则必须扫描更大量的表以使行更新。 我会尝试一个索引,甚至可能是item_id的主键吗?

对于这样的机器和相对较小的数据库来说,持续时间的增加似乎仍然太高。

答案 1 :(得分:0)

鉴于正确诊断需要更多细节(见下文),我认为这有两种潜在的性能降低可能性。

一个是你遇到了Schlemiel the Painter的问题,你可以用它来改善

CREATE INDEX table_ndx ON table(allocated_node, item);

但基数如此之低似乎不太可能。 MySQL不需要这么长时间才能找到未分配的节点。

更可能的解释是,您在客户端之间遇到某种类型的锁定冲突。可以肯定的是,在系统停止的300秒内,运行

SHOW FULL PROCESSLIST

从管理员连接到MySQL。看看它有什么用,并可能用它来更新你的问题。另外,发布

的结果
SHOW CREATE TABLE 

针对您正在使用的表格。

你应该这样做:

START TRANSACTION;
allocate up to 40 nodes using SELECT...FOR UPDATE;
COMMIT WORK;
-- The two transactions serve to ensure that the node selection can
-- never lock more than those 40 nodes. I'm not too sure of that LIMIT
-- being used in the UPDATE.

START TRANSACTION;
select those 40 nodes with SELECT...FOR UPDATE;
<long work involving those 40 nodes and nothing else>
COMMIT WORK;

如果您使用单个事务和表级锁定(甚至是隐式),则可能会发生一个客户端将所有其他客户端锁定。从理论上讲,这应该只发生在MyISAM表中(只有表级锁定),但我也看到线程在InnoDB表中已经停滞了很长时间。

答案 2 :(得分:0)

你的“外部锁定”技术听起来不错。

consumer.instance.timeout.ms会对第一个INDEX(allocated_node)有显着帮助。

UPDATE将有助于最终INDEX(item)

(具有两列的复合索引将仅帮助其中一个更新,而不是两者。)

突然增加的原因:你不断填补大UPDATE字段,使表格大小增加。在某些时候,表是如此之大,以至于它无法缓存在RAM中。因此,它从缓存变为全表扫描。

TEXT - 由于...; SELECT ... FOR UPDATE; COMMIT;立即发生,FOR UPDATE无效。

你可以玩“40”,但我想不出为什么一个更大或更小的数字会有所帮助。