MySQL Connector / ODBC 5.2.2中服务器端预处理语句的问题

时间:2012-11-25 23:57:41

标签: c# mysql odbc

背景

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

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)

我的发现

Google给了我以下interesting result

阅读上面的博客文章后,我开始尝试,当然,当更新到新的ODBC驱动程序(5.2.2,又称“MySQL ODBC 5.2w驱动程序”)时,所有语句现在默认都是服务器端准备的。 (另见公告here)。

以下是使用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%";,现在它给出了以下结果,所以看起来服务器 清理语句,但为时已晚(考虑到上面的错误信息)。即使在30分钟后,最后一个仍然未被封闭(Com_stmt_reset)。

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

announcement提到可以通过向连接字符串添加no_ssps=1选项来禁用服务器端准备。这似乎工作(只是简单地测试了它),但它不是一个坚实的解决方案。我宁愿尽可能多地使用默认值,因为我希望MySQL开发人员知道最佳实践是什么。可能我做错了什么或者没有正确理解事情。

问题

如果服务器现在将我的常规语句转换为预准备语句(而不是旧的客户端模拟),为什么不及时清理它以避免上述错误?

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

如果有人能够对此有所了解,我会非常感激。不幸的是它是00:55所以我现在不能熬夜回答/澄清事情,但明天早上会再次办理登机手续。

1 个答案:

答案 0 :(得分:1)

这是已提交并批准补丁的known bug。你可以:

  • 等待固定发布;
  • 自行应用补丁并重新编译;
  • 降级到5.1;或
  • 使用no_ssps=1