Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Lỗi MySQL 1436:Chạy tràn ngăn xếp luồng, với truy vấn đơn giản

1436 - Chạy tràn ngăn xếp luồng:6136 byte được sử dụng cho ngăn xếp 131072 byte và cần 128000 byte.

Lỗi 1436 tương ứng với ER_STACK_OVERRUN_NEED_MORE trong mã 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

Mã in lỗi được thấy là trong 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));

Từ các giá trị đã thấy, margin là 128000 và my_thread_stack_size là 131072.

Lệnh gọi duy nhất tới check_stack_overrun () cố gắng dự trữ 128000 byte là từ:

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

Giá trị của STACK_MIN_SIZE là 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.

Cho đến nay, mọi thứ hoạt động như mong đợi đối với máy chủ:

  • mã thực thi một trình kích hoạt, được triển khai vớisp_head ::execute.
  • thời gian chạy MySQL kiểm tra xem có ít nhất 128000 byte trên ngăn xếp
  • quá trình kiểm tra này không thành công (đúng như vậy) và quá trình thực thi trình kích hoạt kết thúc bằng lỗi.

Số lượng ngăn xếp cần thiết để thực thi trình kích hoạt MySQL không phụ thuộc vào độ phức tạp của chính trình kích hoạt hoặc nội dung / cấu trúc của các bảng có liên quan.

What the real câu hỏi là, tôi đoán, tại sao thread_stack chỉ ở 128K (131072).

Biến máy chủ có tên 'thread_stack' được triển khai trong C là 'my_thread_stack_size' trong 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 là giá trị tối thiểu cho tham số này. Giá trị mặc định là DEFAULT_THREAD_STACK, được xác định trong 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

Vì vậy, theo mặc định, kích thước ngăn xếp phải là 192K (32bits) hoặc 256K (kiến trúc 64bits).

Trước tiên, hãy kiểm tra cách nhị phân mysqld được biên dịch để xem giá trị mặc định là gì:

[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

Trên hệ thống của tôi, tôi nhận được 256K trên nền tảng 64 bit.

Nếu có các giá trị khác nhau, có thể ai đó xây dựng máy chủ với các tùy chọn biên dịch khác nhau, chẳng hạn như -DDEFAULT_THREAD_STACK (hoặc chỉ sửa đổi nguồn) ... Tôi sẽ đặt câu hỏi rằng tệp nhị phân đến từ đâu trong trường hợp đó.

Thứ hai, hãy kiểm tra my.cnf để biết các giá trị mặc định được cung cấp trong chính tệp cấu hình. Một dòng đặt giá trị thành thread_stack một cách rõ ràng (và với giá trị thấp) chắc chắn sẽ gây ra lỗi được nhìn thấy.

Cuối cùng, hãy kiểm tra tệp nhật ký máy chủ để tìm lỗi như sau (xem sql / mysqld.cc):

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

Mã máy chủ gọi:

  • pthread_attr_setstacksize () để đặt kích thước ngăn xếp
  • pthread_attr_getstacksize () để xác minh xem một luồng thực sự có bao nhiêu ngăn xếp và phàn nàn trong nhật ký nếu thư viện pthread được sử dụng ít hơn.

Tóm lại, lỗi xảy ra do thread_stack quá nhỏ so với các giá trị mặc định được gửi cùng với máy chủ. Điều này có thể xảy ra:

  • khi thực hiện các bản dựng tùy chỉnh của máy chủ, với các lựa chọn biên dịch khác nhau
  • khi thay đổi giá trị mặc định trong tệp my.cnf
  • nếu có sự cố xảy ra trong chính thư viện pthread (về lý thuyết là khi đọc mã, bản thân tôi chưa bao giờ thấy điều đó).

Tôi hy vọng câu trả lời cho câu hỏi này.

Trân trọng, - Marc Alff

Cập nhật (2014-03-11), để làm cho "cách khắc phục" rõ ràng hơn.

Điều gì đang xảy ra, rất có thể, là giá trị mặc định cho tệp thread_stack đã bị thay đổi trong tệp my.cnf.

Sau đó, cách khắc phục nó rất đơn giản, hãy tìm nơi thread_stack được đặt trong tệp my.cnf và xóa cài đặt (tin tưởng mã máy chủ cung cấp giá trị mặc định phù hợp, vì vậy điều này sẽ không xảy ra lần sau) hoặc tăng ngăn xếp kích thước.

Cập nhật (2021-04-28), kiểm tra thread_stack đến từ đâu:

Sử dụng bảng performance_schema.variables_info để tìm hiểu xem một biến nhất định đến từ đâu.

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)

Ở đây, giá trị mặc định là giá trị ban đầu (được biên dịch trong hệ nhị phân mysqld).

Một ví dụ khác:

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)

Ở đây, thread_stack được đặt trong tệp my.cnf được báo cáo.

Người giới thiệu:

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào tôi có thể sử dụng thực thi để chèn vào MySQL một danh sách các từ điển bằng Python

  2. Truy vấn tham số MySQL

  3. Nhân bản, sao chép hoặc sao lưu bảng trong MySQL, MariaDB, Oracle, PostgreSQL, DB2 và SQLite với Tạo bảng dưới dạng SQL

  4. Ví dụ về TIMESTAMP () - MySQL

  5. Khóa chính MySQL