4

背景

我收到了一位客户的报告,他抱怨说,在他们的服务器上执行了一些更新后,他们的日志文件中出现了以下错误消息:

ERROR [HY000] [MySQL][ODBC 5.2(w) Driver][mysqld-5.1.49]Can't create more than max_prepared_stmt_count statements (current value: 16382)

我的发现

谷歌给了我以下有趣的结果

在阅读了上面的博客文章后,我开始进行实验,果然 - 当更新到新的 ODBC 驱动程序(5.2.2,又名“MySQL ODBC 5.2w 驱动程序”)时,所有语句现在默认情况下都是服务器端准备的。(另请参阅此处的公告)。

这是使用 5.2.2 的全局日志中的两行:

[192.168.0.150]|134302|0|Prepare|INSERT INTO `a1gt6` (`TimeStamp`, `Temperature`) VALUES (?, ? )
[192.168.0.150]|134302|0|Execute|INSERT INTO `a1gt6` (`TimeStamp`, `Temperature`) VALUES ('2012-11-25 12:40:27', '7.03750000000000000e+001' )

问题

如果不是因为它们显然没有被服务器关闭(及时,请参阅下面的更新),我的语句被转换为准备好的语句,我不会有什么大问题,如上述错误所示消息和命令的结果show global status like "com_stmt%";

Com_stmt_close  0
Com_stmt_execute    1
Com_stmt_fetch  0
Com_stmt_prepare    1
Com_stmt_reprepare  0
Com_stmt_reset  0
Com_stmt_send_long_data 0

上表显示了使用 Connector/ODBC 5.2.2 单次运行语句后的结果。下面是show global status like "com_stmt%";使用 Connector/ODBC/5.1.11的输出

Com_stmt_close  0
Com_stmt_execute    0
Com_stmt_fetch  0
Com_stmt_prepare    0
Com_stmt_reprepare  0
Com_stmt_reset  0
Com_stmt_send_long_data 0

下面是我用来确定问题原因的 C# 测试方法。

[TestMethod]
public void TestOldfashion()
{
    int option = 16 + /*FLAG_MULTI_STATEMENTS*/ 67108864;
    string odbcString = @"DRIVER={{{0}}};SERVER={1};UID={2};PWD={3};OPTION=" + option + ";CharSet=utf8;";
    using( System.Data.Odbc.OdbcConnection con = new System.Data.Odbc.OdbcConnection( string.Format( odbcString, new object[] { "MySQL ODBC 5.1 Driver", "server", "user", "password" } ) ) ) {
        con.Open();
        con.ChangeDatabase( "fooDB" );
        using( System.Data.Odbc.OdbcCommand cmd = con.CreateCommand() ) {
            cmd.CommandText = "INSERT INTO myTable ( foo, value ) VALUES ( ?, ? );";
            cmd.Parameters.AddWithValue( "foo", 2 );
            cmd.Parameters.AddWithValue( "value", "asf" );
            int i = cmd.ExecuteNonQuery();
        }
    }
}

这是表的 CREATE 语句:

delimiter $$

CREATE TABLE `mytable` (
  `index` int(11) NOT NULL AUTO_INCREMENT,
  `foo` float DEFAULT NULL,
  `value` text,
  PRIMARY KEY (`index`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8$$

发布前更新

就在提出这个之前,我show global status like "com_stmt%";再次执行了,现在它给出了以下结果,所以看起来服务器确实清理了语句,但为时已晚(考虑到上述错误消息)。Com_stmt_reset即使在 30 分钟后,最后一个仍然未关闭(in )。

Com_stmt_close  6
Com_stmt_execute    7
Com_stmt_fetch  0
Com_stmt_prepare    7
Com_stmt_reprepare  0
Com_stmt_reset  1
Com_stmt_send_long_data 0

公告提到可以通过将no_ssps=1选项添加到连接字符串来禁用服务器端准备。这似乎有效(仅对其进行了简要测试),但感觉不像是一个可靠的解决方案。我宁愿尽可能地使用默认值,因为我希望 MySQL 开发人员知道最佳实践是什么。可能我做错了什么或没有正确理解事情。

问题

如果服务器现在将我的常规语句转换为准备好的语句(与旧的客户端仿真相反),为什么不及时清理它以避免上述错误?

我希望在 OdbcCommand 的使用范围结束时关闭/释放该语句,但这显然不正确?

如果有人能对此有所了解,我将不胜感激。不幸的是,现在是 00:55,所以我现在不能熬夜回答/澄清事情,但明天早上会再次检查。

4

1 回答 1

2

这是一个已知的错误,补丁已提交并获得批准。你可以:

  • 等待固定版本;
  • 自己应用补丁并重新编译;
  • 降级到 5.1;或者
  • 使用no_ssps=1.
于 2012-11-26T00:08:28.670 回答