MySQL存储过程的奇怪性能问题,它将许多INSERT插入临时表

时间:2017-11-27 00:02:08

标签: mysql performance stored-procedures sql-insert

修改和改进的问题:

我的MySQL服务器有一个奇怪的问题。这是一个例子,简化为一个简单的问题:

drop procedure if exists temp_test;
create procedure temp_test()
begin
  declare i int default 0;

  drop temporary table if exists temp_table;
  create temporary table temp_table(x int) engine = memory;

  while i < 400 do
    insert into temp_table(x) values (i);
    set i = i + 1;
  end while; 

  select * from temp_table;
end;

调用此过程大约需要1秒,这比我预期的要长。但!这是在距离大约1500公里的数据中心的远程服务器上(Amazon RDS)。如果我在我的本地MySQL实例上运行它,这需要不到0.1秒。我可以排除网络延迟 - 在远程服务器上运行简单的select 1;只需0.15秒。

Weirder,有一分钟,远程服务器同样快(加上网络延迟)!然后它再次变得缓慢。但它没有加载 - 这只是一个测试服务器,而我现在是唯一一个访问它的人。

发生了什么事?我应该在哪里看?

(抢先回复:不,在完整问题上我无法将其缩减为单INSERT ... SELECT

1 个答案:

答案 0 :(得分:2)

我自己想出来了!

远程服务器是Amazon RDS服务器。我认为它不重要,但显然它们因其二进制复制日志的性能降低而臭名昭着(作为旁注,为什么我们为那些永远不会被复制的 test 服务器启用了它我,但无论如何)。

你会认为带有内存存储引擎的临时表不会使用它或以任何方式触摸磁盘,但你会错的。显然,它仍然可以进入binlog,而且它们都被复制了。

现在,MySQL有一个名为sync_binlog的选项 - 它是一个整数,用于说明将binlog从内存缓冲区刷新到磁盘的事务数。 0表示操作系统决定何时刷新文件(就像大多数文件一样); 1表示每次交易后都会刷新; 2表示每个其他交易等。默认值为 1 - 每次交易后刷新。

最后一个难题是MEMORY存储引擎不支持事务。因此,就MySQL而言,每个INSERT实际上都是一个完整的事务。你可以看到它的发展方向。

解决方案违反直觉但有效 - 从MEMORY更改为InnoDB并将其全部放入交易中。繁荣。现在整个过程需要0.2秒,这包括0.15秒的网络延迟。这还差不多! :)