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を使用したグローバルログからの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 /ODBC5.2.2を使用してステートメントを1回実行した後の結果を示しています。以下は、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のusing-scopeの終わりに達したときにステートメントが閉じられる/解放されることを期待しますが、それは明らかに間違っていますか?

誰かがこれに光を当てることができれば幸いです。残念ながら00:55なので、今は答えたり明確にしたりすることはできませんが、明日の朝にまたチェックインします。

4

1 に答える 1

2

これは、パッチが送信および承認された既知のバグです。あなたはできる:

  • 修正されたリリースを待ちます。
  • 自分でパッチを適用して再コンパイルします。
  • 5.1にダウングレードします。また
  • を使用しますno_ssps=1
于 2012-11-26T00:08:28.670 に答える