MySQL错误1436:线程堆栈溢出,简单查询

时间:2012-01-11 15:10:05

标签: mysql triggers

我正在对表进行非常简单的更新,这也会触发一个非常简单的触发器,它会给我错误

#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

值字段是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 ;

为什么会显示此错误?这不像是涉及任何繁重的查询。另请注意,数据库几乎为空,community_fields_values只有2行,而user_field_log

中没有行

MySQL版本:5.1.44

2 个答案:

答案 0 :(得分:53)

1436 - 线程堆栈溢出:使用了131072字节堆栈的6136个字节,需要128000个字节。

错误1436对应于mysql 5.1代码中的ER_STACK_OVERRUN_NEED_MORE:

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。

尝试保留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:

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 ::执行。
  • 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二进制文件是如何编译的,看看默认值是什么:

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

在我的系统上,我在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),使“如何修复”更加明显。

最有可能的是,my.cnf文件中的thread_stack文件的默认值已更改。

如何修复它是微不足道的,找到my.cnf文件中设置thread_stack的位置,并删除设置(信任服务器代码以提供合适的默认值,因此下次不会再发生这种情况)或者增加堆栈大小。

答案 1 :(得分:33)

虽然不是解决方案,但快速修复可能是通过在my.cnf中递增来增加thread_stack大小:

thread_stack = 256K

正如用户“foo”指出的那样,发布整个触发器代码可能更有助于检测真正的问题。