Mysql
 sql >> Database >  >> RDS >> Mysql

Errore MySQL 1436:sovraccarico dello stack di thread, con query semplice

1436 - Sovraccarico dello stack di thread:6136 byte utilizzati su uno stack di 131072 byte e 128000 byte necessari.

L'errore 1436 corrisponde a ER_STACK_OVERRUN_NEED_MORE nel codice MySQL 5.1:

[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

Il codice che stampa l'errore visto è in 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));

Dai valori visti, il margine è 128000 e my_thread_stack_size è 131072.

L'unica chiamata a check_stack_overrun() che tenta di riservare 128000 byte proviene da:

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);

Il valore di 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.

Finora, tutto funziona come previsto per il server:

  • il codice esegue un trigger, che viene implementato consp_head::execute.
  • il runtime MySQL verifica che ci siano almeno 128000 byte nello stack
  • questo controllo fallisce (giustamente) e l'esecuzione del trigger termina con un errore.

La quantità di stack necessaria per l'esecuzione del trigger MySQL non dipende dalla complessità del trigger stesso o dal contenuto/struttura delle tabelle coinvolte.

Che cosa è reale la domanda è, suppongo, perché thread_stack è solo a 128K (131072).

La variabile del server denominata 'thread_stack' è implementata in C come 'my_thread_stack_size' in sql/mysqld.cc :

  {"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 è il valore minimo per questo parametro. Il valore predefinito è DEFAULT_THREAD_STACK, definito in 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

Quindi, per impostazione predefinita, la dimensione dello stack dovrebbe essere 192 K (32 bit) o ​​256 K (architetture a 64 bit).

Per prima cosa, controlla come è stato compilato il binario mysqld, per vedere qual è il valore predefinito:

[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

Sul mio sistema, ho ottenuto 256K su una piattaforma a 64 bit.

Se ci sono valori diversi, forse qualcuno crea il server con diverse opzioni di compilazione, come -DDEFAULT_THREAD_STACK (o ha appena modificato il sorgente) ... Mi chiederei da dove proviene il binario in quel caso.

In secondo luogo, controlla my.cnf per i valori predefiniti forniti nel file di configurazione stesso. Una riga che imposta un valore su thread_stack in modo esplicito (e con un valore basso) causerebbe definitivamente l'errore visualizzato.

Infine, controlla il file di registro del server per un errore come questo (vedi sql/mysqld.cc):

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

Il codice del server chiama:

  • pthread_attr_setstacksize() per impostare la dimensione dello stack
  • pthread_attr_getstacksize() per verificare quanto stack ha realmente un thread e si lamenta nel log se la libreria pthread ne usa meno.

Per farla breve, l'errore viene visualizzato perché thread_stack è troppo piccolo rispetto ai valori predefiniti forniti con il server. Questo può accadere:

  • quando si eseguono build personalizzate del server, con diverse opzioni di compilazione
  • quando si modifica il valore predefinito nel file my.cnf
  • se qualcosa è andato storto nella libreria pthread stessa (in teoria leggendo il codice, non l'ho mai visto di persona).

Spero che questo risponda alla domanda.

Saluti,-- Marc Alff

Aggiornamento (11-03-2014), per rendere più ovvio il "come risolvere".

Quello che sta succedendo, con ogni probabilità, è che il valore predefinito per il file thread_stack è stato modificato nel file my.cnf.

Come risolverlo è banale quindi, trova dove thread_stack è impostato nel file my.cnf e rimuovi l'impostazione (fidandoti che il codice del server fornisca un valore predefinito decente, quindi ciò non accada di nuovo la prossima volta) o aumenta lo stack taglia.

Aggiornamento (2021-04-28), controlla da dove viene thread_stack:

Usa la tabella performance_schema.variables_info per scoprire da dove proviene una determinata variabile.

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)

Qui il valore predefinito è il valore di fabbrica (compilato nel binario mysqld).

Un altro esempio:

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)

Qui il thread_stack è impostato nel file my.cnf riportato.

Referente:

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