Rails 3.2.3 mysql错误“max_prepared_stmt_count”

时间:2012-12-12 21:32:23

标签: mysql ruby-on-rails-3.2

我在带有mysql数据库服务器的虚拟主机上运行使用apache2 / passenger部署的Rails 3.2.3应用程序。在很多流量进入网站后我收到了这个错误:

ActiveRecord::StatementInvalid (Mysql::Error: Can't create more than 
max_prepared_stmt_count statements (current value: 16382)

我认为这与流量有关,但如果是这样,我必须找到解决方法。以前有人有这个错误吗?我无法弄清楚如何阻止它。

这是我在mysql中看到的:

的MySQL>显示全球状态,例如'com_stmt%';

| Com_stmt_close | 1720319 | Com_stmt_execute | 2094137 |

| Com_stmt_fetch | 0 |

| Com_stmt_prepare | 1768924 |

| Com_stmt_reprepare | 0 |

| Com_stmt_reset | 0 |

| Com_stmt_send_long_data | 0 |

+ ------------------------- + --------- +

我正在运行resque gem。

2 个答案:

答案 0 :(得分:2)

好的,我暂时在试试这里的答案。我使用femtoRgon的提示来检查状态。然后我将这两行添加到我的database.yml文件

  pool: 30
  prepared_statements: false

我重启了mysql。现在让应用程序运行一段时间后,我看到了这一点:

mysql> show global status like 'com_stmt%';

| Com_stmt_close          | 189017 |

| Com_stmt_execute        | 189017 |

| Com_stmt_fetch          | 0      |

| Com_stmt_prepare        | 189017 |

| Com_stmt_reprepare      | 0      |

| Com_stmt_reset          | 0      |

| Com_stmt_send_long_data | 0      |

在任何地方都没有差异......加上我用来看到这个:

Ecard Load (0.1ms)  SELECT `ecards`.* FROM `ecards` WHERE `ecards`.`id` = ? LIMIT 1  [["id", "34"]] 

我现在看到了:

Ecard Load (0.4ms)  SELECT `ecards`.* FROM `ecards` WHERE `ecards`.`id` = 34 LIMIT 1

我认为这表明我不再使用预备语句了?会喜欢任何想法 - 我想我必须继续监控,看看情况如何......

答案 1 :(得分:1)

很可能正在打开针对数据库的准备语句,而不是关闭它们。

要检查这一点,请尝试查询:

show global status like ‘com_stmt%’;

Com_stmt_prepare和Com_stmt_close之间存在非常大的差异,这表明某些事项会使准备好的语句保持打开状态。当然,Com_stmt_close = 0会特别有说服力。


虽然两者之间的差异相对较小,但实际上您确实需要同时进行多次公开声明,但我仍然认为您更有可能将它们泄漏到某处(错误) /边缘案例处理,是人们经常忘记关闭资源的典型例子。)

您可以增加允许的语句数量:

set global max_prepared_stmt_count=<some_larger number>;

哪个应该让事情再次滚动。小心太高的限制,因为这可能让你容易受到DoS的攻击。<​​/ p>

之后,我会对其进行监控,并查看是否会随着时间的推移积累更多准备好的报表。

如果你:

set global general_log = 'ON';

常规日志将记录Prepare个语句。寻找没有匹配关闭的任何一个,以帮助找到任何此类问题。