sql >> データベース >  >> RDS >> Mysql

MySQLエラー1436:単純なクエリでスレッドスタックがオーバーランしました

    1436-スレッドスタックオーバーラン:131072バイトスタックで6136バイトが使用され、128000バイトが必要です。

    エラー1436は、mysql 5.1コードのER_STACK_OVERRUN_NEED_MOREに対応します:

    [email protected]:include> pwd
    /home/malff/BZR_TREE/mysql-5.1/include
    [email protected]:include> grep 1436 mysqld_error.h
    #define ER_STACK_OVERRUN_NEED_MORE 1436
    

    表示されたエラーを出力するコードは、sql / sql_parse.cc、function check_stack_overrun()にあります:

    bool check_stack_overrun(THD *thd, long margin,
                             uchar *buf __attribute__((unused)))
    {
      long stack_used;
      DBUG_ASSERT(thd == current_thd);
      if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
          (long) (my_thread_stack_size - margin))
      {
        char ebuff[MYSQL_ERRMSG_SIZE];
        my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
                    stack_used, my_thread_stack_size, margin);
        my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));
    

    表示された値から、マージンは128000、my_thread_stack_sizeは131072です。

    128000バイトを予約しようとするcheck_stack_overrun()の唯一の呼び出しは、次のとおりです。

    bool
    sp_head::execute(THD *thd)
    {
      /* Use some extra margin for possible SP recursion and functions */
      if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
        DBUG_RETURN(TRUE);
    

    STACK_MIN_SIZEの値は16000です:

    [email protected]:sql> pwd
    /home/malff/BZR_TREE/mysql-5.1/sql
    [email protected]:sql> grep STACK_MIN_SIZE *.h
    mysql_priv.h:#define STACK_MIN_SIZE          16000   // Abort if less stack during eval.
    

    これまでのところ、サーバーではすべてが期待どおりに機能しています。

    • コードは、sp_head::executeで実装されるトリガーを実行します。
    • MySQLランタイムは、スタックに少なくとも128000バイトがあることを確認します
    • このチェックは失敗し(当然のことながら)、トリガーの実行はエラーで終了します。

    MySQLトリガーの実行に必要なスタックの量は、トリガーの複雑さ自体、または関連するテーブルのコンテンツ/構造に依存しません。

    本物 問題は、なぜthread_stackが128K(131072)しかないのかということです。

    'thread_stack'という名前のサーバー変数は、Cではsql /mysqld.ccの'my_thread_stack_size'として実装されています:

      {"thread_stack", OPT_THREAD_STACK,
       "The stack size for each thread.", &my_thread_stack_size,
       &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
       1024L*128L, ULONG_MAX, 0, 1024, 0},
    

    1024L * 128Lは、このパラメーターの最小値です。デフォルト値はDEFAULT_THREAD_STACKで、include / my_pthread.h:

    で定義されています。
    #ifndef DEFAULT_THREAD_STACK
    #if SIZEOF_CHARP > 4
    /*
      MySQL can survive with 32K, but some glibc libraries require > 128K stack
      To resolve hostnames. Also recursive stored procedures needs stack.
    */
    #define DEFAULT_THREAD_STACK    (256*1024L)
    #else
    #define DEFAULT_THREAD_STACK    (192*1024)
    #endif
    #endif
    

    したがって、デフォルトでは、スタックサイズは192K(32ビット)または256K(64ビットアーキテクチャ)である必要があります。

    まず、mysqldバイナリがどのようにコンパイルされたかを確認し、デフォルト値を確認します。

    [email protected]:sql> pwd
    /home/malff/BZR_TREE/mysql-5.1/sql
    [email protected]:sql> ./mysqld --no-defaults --verbose --help | grep thread_stack
    ...
      --thread_stack=#    The stack size for each thread.
    thread_stack                      262144
    

    私のシステムでは、64ビットプラットフォームで256Kを取得しました。

    値が異なる場合は、誰かが-DDEFAULT_THREAD_STACK(またはソースを変更しただけ)などの異なるコンパイルオプションを使用してサーバーを構築している可能性があります...その場合、バイナリはどこから来ているのか疑問に思います。

    次に、my.cnfで、構成ファイル自体に提供されているデフォルト値を確認します。値をthread_stackに明示的に(そして低い値で)設定する行は、間違いなくエラーを引き起こします。

    最後に、サーバーログファイルで次のようなエラーがないか確認します(sql / mysqld.ccを参照):

    sql_print_warning("Asked for %lu thread stack, but got %ld",
                      my_thread_stack_size, (long) stack_size);
    

    サーバーコードの呼び出し:

    • スタックサイズを設定するためのpthread_attr_setstacksize()
    • pthread_attr_getstacksize()を使用して、スレッドが実際に持っているスタックの量を確認し、pthreadライブラリの使用量が少ない場合はログに文句を言います。

    簡単に言うと、サーバーに付属しているデフォルト値と比較してthread_stackが小さすぎるためにエラーが発生します。これは、次の場合に発生する可能性があります。

    • さまざまなコンパイルオプションを使用してサーバーのカスタムビルドを実行する場合
    • my.cnfファイルのデフォルト値を変更する場合
    • pthreadライブラリ自体に問題が発生した場合(理論的には、コードを読んだことから、私はそれを自分で見たことがありません)。

    これが質問に答えることを願っています。

    よろしく、-マークアルフ

    「修正方法」をより明確にするための更新(2014-03-11)。

    おそらく起こっていることは、thread_stackファイルのデフォルト値がmy.cnfファイルで変更されたことです。

    それを修正する方法は簡単です。my.cnfファイルのどこにthread_stackが設定されているかを見つけ、設定を削除するか(サーバーコードを信頼して適切なデフォルト値を提供するため、次回はこれが再び発生しません)、スタックを増やします。サイズ。

    アップデート(2021-04-28)、thread_stackの出所を確認してください:

    テーブルperformance_schema.variables_infoを使用します 与えられた変数がどこから来たのかを知るために。

    mysql> select * from variables_info where VARIABLE_NAME = 'thread_stack';
    +---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
    | VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH | MIN_VALUE | MAX_VALUE            | SET_TIME | SET_USER | SET_HOST |
    +---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
    | thread_stack  | COMPILED        |               | 131072    | 18446744073709550592 | NULL     | NULL     | NULL     |
    +---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
    1 row in set (0.01 sec)
    

    ここでのデフォルトは工場出荷時の値です(mysqldバイナリでコンパイルされます)。

    別の例:

    mysql> select * from variables_info where VARIABLE_NAME = 'thread_stack';
    +---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
    | VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH                                                  | MIN_VALUE | MAX_VALUE            | SET_TIME | SET_USER | SET_HOST |
    +---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
    | thread_stack  | EXPLICIT        | /home/malff/CODE/GIT/GIT_TRUNK/build-dbg/mysql-test/var/my.cnf | 131072    | 18446744073709550592 | NULL     | NULL     | NULL     |
    +---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
    1 row in set (0.00 sec)
    

    ここで、thread_stackは、報告されたmy.cnfファイルに設定されています。

    Refman:

    https://dev.mysql .com / doc / refman / 8.0 / en / performance-schema-variables-info-table.html



    1. SQLiteでユリウス日を返す2つの方法

    2. MySQLGaleraクラスター間で非同期レプリケーションを設定する方法

    3. mysqlデータベース全体を見つけて置き換えます

    4. SQL Serverのsys.sql_modules、sys.system_sql_modules、およびsys.all_sql_modulesの違い