我在带有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。
答案 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
个语句。寻找没有匹配关闭的任何一个,以帮助找到任何此类问题。