sql >> Databasteknik >  >> RDS >> Mysql

MySQL-fel 1436:Överskriden trådstack, med enkel fråga

1436 - Trådstack överskriden:6136 byte används av en 131072 byte stack och 128000 byte behövs.

Felet 1436 motsvarar ER_STACK_OVERRUN_NEED_MORE i mysql 5.1-koden :

[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

Koden som skriver ut felet finns i 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));

Från värdena som visas är marginalen 128000 och my_thread_stack_size är 131072.

Det enda anropet till check_stack_overrun() som försöker reservera 128000 byte är från:

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

Värdet på STACK_MIN_SIZE är 16 000:

[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.

Än så länge fungerar allt som förväntat för servern:

  • koden kör en utlösare, som implementeras med sp_head::execute.
  • MySQL-körtiden kontrollerar att det finns minst 128 000 byte i stacken
  • denna kontroll misslyckas (med rätta), och utlösarkörningen slutar med ett fel.

Mängden stack som behövs för att köra MySQL-utlösaren beror inte på själva triggerkomplexiteten eller innehållet/strukturen i de inblandade tabellerna.

Vad är det riktiga Frågan är, antar jag, varför thread_stack endast är på 128K (131072).

Servervariabeln med namnet 'thread_stack' är implementerad i C som 'my_thread_stack_size' i 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 är minimivärdet för denna parameter. Standardvärdet är DEFAULT_THREAD_STACK, vilket definieras i 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

Så som standard bör stackstorleken vara 192K (32bitar) eller 256K (64bitarsarkitekturer).

Kontrollera först hur mysqld-binären kompilerades för att se vad som är standardvärdet:

[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

På mitt system fick jag 256K på en 64-bitars plattform.

Om det finns olika värden kanske någon bygger servern med olika kompileringsalternativ, till exempel -DDEFAULT_THREAD_STACK (eller modifierade bara källan) ... Jag skulle ifrågasätta var binären kommer ifrån i så fall.

För det andra, kontrollera my.cnf för standardvärden som finns i själva konfigurationsfilen. En rad som anger ett värde till thread_stack uttryckligen (och med ett lågt värde) skulle definitivt orsaka felet som visas.

Se sist, kontrollera serverloggfilen för ett fel som detta (se sql/mysqld.cc) :

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

Serverkoden anropar:

  • pthread_attr_setstacksize() för att ställa in stackstorleken
  • pthread_attr_getstacksize() för att verifiera hur mycket stack en tråd verkligen har och klagar i loggen om pthread-biblioteket använde mindre.

Lång historia kort, felet visas eftersom thread_stack är för liten jämfört med standardvärdena som levereras med servern. Detta kan hända:

  • när man gör anpassade builds av servern, med olika kompileringsalternativ
  • när du ändrar standardvärdet i my.cnf-filen
  • om något gick fel i själva pthread-biblioteket (i teorin efter att jag läste koden har jag aldrig sett det själv).

Jag hoppas att detta svarar på frågan.

Hälsningar,-- Marc Alff

Uppdatering (2014-03-11), för att göra "hur man fixar" mer uppenbart.

Det som med all sannolikhet händer är att standardvärdet för filen thread_stack ändrades i filen my.cnf.

Hur man fixar det är trivialt då, hitta var thread_stack är inställd i my.cnf-filen och antingen ta bort inställningen (lita på att serverkoden ger ett anständigt standardvärde, så att detta inte händer igen nästa gång) eller öka stacken storlek.

Uppdatera (2021-04-28), kolla var thread_stack kommer ifrån:

Använd tabellen performance_schema.variables_info för att ta reda på var en given variabel kommer ifrån.

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)

Här är standardvärdet fabriksvärdet (kompilerat i mysqld-binären).

Ett annat exempel:

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)

Här är thread_stack inställd i my.cnf-filen som rapporteras.

Refman:

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



  1. Vad gör ::i PostgreSQL?

  2. Vilka är de huvudsakliga prestandaskillnaderna mellan varchar och nvarchar SQL Server-datatyper?

  3. SQLite - Säkerhetskopiera en databas till fil

  4. Ska jag använda !=eller <> för inte lika i T-SQL?