Ошибка MySQL 1436: переполнение стека строк, с простым запросом

Я делаю очень простое обновление таблицы, которое также запускает действительно простой триггер, и это дает мне ошибку

#1436 - Thread stack overrun: 6136 bytes used of a 131072 byte stack, and 128000 bytes needed. 

Выполняемый запрос:

 UPDATE field_values SET value = 'asaf' WHERE field_values.id =1 

Поле value – text поле. Так что теоретически это может стать тихим большим. Это не так в этой ситуации.

Запуск триггера:

 DELIMITER $$ CREATE TRIGGER field_value_update_trigger BEFORE UPDATE ON community_fields_values FOR EACH ROW BEGIN INSERT INTO user_field_log (user_id, field_id, value) VALUES (NEW.user_id, NEW.field_id, NEW.value); END; $$ DELIMITER ; 

Почему эта ошибка отображается? Это не похоже на какой-либо тяжелый запрос. Также обратите внимание, что firebase database почти пуста, всего 2 строки в community_fields_values и без строк в user_field_log

Версия MySQL: 5.1.44

2 Solutions collect form web for “Ошибка MySQL 1436: переполнение стека строк, с простым запросом”

1436 – Переполнение стека streamов: 6136 байт, используемых в стеке 131072 байт, и 128000 байт.

Ошибка 1436 соответствует значению ER_STACK_OVERRUN_NEED_MORE в коде mysql 5.1:

 malff@linux-8edv:include> pwd /home/malff/BZR_TREE/mysql-5.1/include malff@linux-8edv: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.

Единственный вызов check_stack_overrun (), который пытается зарезервировать 128000 байт, – это:

 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:

 malff@linux-8edv:sql> pwd /home/malff/BZR_TREE/mysql-5.1/sql malff@linux-8edv: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 как «my_thread_stack_size» в 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 – минимальное значение для этого параметра. Значение по умолчанию – 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 

Таким образом, по умолчанию размер стека должен быть 192 Кбит (32 бита) или 256 КБ (архитектуры 64 бит).

Сначала проверьте, как скомпилирован бинарный файл mysqld, чтобы узнать, что такое значение по умолчанию:

 malff@linux-8edv:sql> pwd /home/malff/BZR_TREE/mysql-5.1/sql malff@linux-8edv:sql> ./mysqld --no-defaults --verbose --help | grep thread_stack ... --thread_stack=# The stack size for each thread. thread_stack 262144 

В моей системе я получил 256 КБ на 64-битной платформе.

Если есть разные значения, возможно, кто-то построит сервер с различными параметрами компиляции, такими как -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 (), чтобы проверить, сколько streamов в streamе действительно существует и жалуется в журнале, если библиотека pthread используется меньше.

Короче говоря, ошибка проявляется, потому что thread_stack слишком мал по сравнению со значениями по умолчанию, поставляемыми с сервером. Это может случиться:

  • при выполнении пользовательских сборок сервера с различными параметрами компиляции
  • при изменении значения по умолчанию в файле my.cnf
  • если что-то пошло не так в самой библиотеке pthread (теоретически, прочитав код, я никогда не видел его сам).

Надеюсь, это ответит на вопрос.

С уважением, – Марк Альфф

Update (2014-03-11), чтобы сделать «как исправить» более очевидным.

По всей видимости, происходит то, что значение по умолчанию для файла thread_stack было изменено в файле my.cnf.

Как исправить это тривиально, найдите, где thread_stack установлен в файле my.cnf, и либо удалите параметр (доверяя серверному коду, чтобы обеспечить достойное значение по умолчанию, так что это не повторится в следующий раз) или увеличить стек размер.

Хотя это и не решение, но быстрое исправление может состоять в том, чтобы увеличить размер thread_stack, увеличив его в my.cnf:

thread_stack = 256K

Как отметил пользователь «foo», размещение всего кода триггера может быть более полезным для обнаружения реальной проблемы.

Давайте будем гением компьютера.