翼度科技»论坛 编程开发 mysql 查看内容

SHOW PROCESSLIST 最多能显示多长的 SQL?

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24
在 MySQL 中,如果我们想查看实例当前正在执行的 SQL,常用的命令是SHOW PROCESSLIST。
但如果 SQL 过长的话,就会被截断。这时,我们一般会用SHOW FULL PROCESSLIST来查看完整的 SQL。
最近碰到一个 case,发现无论是使用 SHOW PROCESSLIST、SHOW FULL PROCESSLIST,还是 performance_schema.processlist 都无法获取完整的 SQL,反倒 information_schema.processlist 可以。
最后发现,SHOW FULL PROCESSLIST无法查看完整的 SQL 竟然与 performance_schema_show_processlist 参数有关。
SHOW PROCESSLIST 的实现方式

SHOW PROCESSLIST默认是从线程管理器(Global_THD_manager)中获取线程信息。
这种实现方式会持有全局互斥锁。在负载高的场景,会对数据库的性能有一定的负面影响。
所以一般都推荐使用 performance_schema.processlist,这种方式不会持有全局锁。
在 MySQL 8.0.22 中,引入了 performance_schema_show_processlist 参数,可设置SHOW PROCESSLIST的实现方式。
当该参数设置为 ON 时,会使用 performance_schema.processlist 的实现方式。
当参数设置为 OFF(默认值) 时,会使用传统的实现方式。
三种不同查询方式对 SQL 的长度限制

下面我们看看 SHOW PROCESSLIST, information_schema.processlist, performance_schema.processlist 这三种不同的查询方式对 SQL 的长度限制。
因为 SQL 是在 INFO 列中存储的,所以,SQL 的最大长度实际上是由 INFO 列决定的。
SHOW PROCESSLIST

SHOW PROCESSLIST的输出中 INFO 列的最大长度与 performance_schema_show_processlist 有关。
当 performance_schema_show_processlist 等于 OFF 时,无论是SHOW PROCESSLIST,还是SHOW FULL PROCESSLIST,调用的都是 mysqld_list_processes 函数。
  1. // sql/sql_show.cc
  2. void mysqld_list_processes(THD *thd, const char *user, bool verbose,
  3.                            bool has_cursor) {
  4.   Item *field;
  5.   mem_root_deque<Item *> field_list(thd->mem_root);
  6.   Thread_info_array thread_infos(thd->mem_root);
  7.   size_t max_query_length =
  8.       (verbose ? thd->variables.max_allowed_packet : PROCESS_LIST_WIDTH);
  9.   Protocol *protocol = thd->get_protocol();
  10.   DBUG_TRACE;
  11.   
  12.   ...
  13.   field_list.push_back(field = new Item_empty_string("Info", max_query_length));
  14.   ...
  15. }
复制代码
可以看到,INFO 列的最大长度由 max_query_length 决定,而 max_query_length 的取值又与 verbose 有关。
当执行SHOW FULL PROCESSLIST时, verbose 为 true,此时 max_query_length 等于 max_allowed_packet。
当执行SHOW PROCESSLIST时,verbose 为 false,此时 max_query_length 等于 PROCESS_LIST_WIDTH,而 PROCESS_LIST_WIDTH 是个常量,大小为 100。
  1. constexpr const size_t PROCESS_LIST_WIDTH{100};
复制代码
当 performance_schema_show_processlist 等于 ON 时,无论是SHOW PROCESSLIST,还是SHOW FULL PROCESSLIST,调用的都是build_processlist_query 函数。
  1. // sql/sql_show_processlist.cc
  2. bool build_processlist_query(const POS &pos, THD *thd, bool verbose) {
  3.   LEX_STRING info_len;
  4.   /*
  5.     Default Info field length is 100. Verbose field length is limited to the
  6.     size of the INFO columns in the Performance Schema.
  7.   */
  8.   assert(PROCESS_LIST_WIDTH == 100);
  9.   if (verbose) {
  10.     if (lex_string_strmake(thd->mem_root, &info_len, "1024", 4)) return true;
  11.   } else {
  12.     if (lex_string_strmake(thd->mem_root, &info_len, "100", 3)) return true;
  13.   }
  14.   ...
  15.   /* Info length is either "100" or "1024" depending on verbose */
  16.   Item_int *item_info_len = new (thd->mem_root) Item_int(pos, info_len);
  17.   if (item_info_len == nullptr) return true;
  18.   ...
  19. }
复制代码
当执行SHOW FULL PROCESSLIST时, verbose 为 true,此时 info_len 等于 1024。
当执行SHOW PROCESSLIST时,verbose 为 false,此时 info_len 等于 100。
information_schema.processlist

information_schema.processlist 表中 INFO 的长度是在Fill_process_list中限制的。
  1. // sql/sql_show.cc
  2. class Fill_process_list : public Do_THD_Impl {
  3.   ...
  4.   void operator()(THD *inspect_thd) override {
  5.     
  6.     /* INFO */
  7.     mysql_mutex_lock(&inspect_thd->LOCK_thd_query);
  8.     {
  9.       const char *query_str = nullptr;
  10.       size_t query_length = 0;
  11.       ...
  12.       if (query_str) {
  13.         const size_t width = min<size_t>(PROCESS_LIST_INFO_WIDTH, query_length);
  14.         table->field[7]->store(query_str, width, inspect_thd->charset());
  15.         table->field[7]->set_notnull();
  16.       }
  17.     }
  18.     ...
  19.   }
  20. };
复制代码
INFO 的长度取 PROCESS_LIST_INFO_WIDTH 和 query_length(SQL 的实际长度)的最小值。
所以,INFO 列的最大长度由 PROCESS_LIST_INFO_WIDTH 决定,而 PROCESS_LIST_INFO_WIDTH 也是个常量,值为 65535。
  1. constexpr const size_t PROCESS_LIST_INFO_WIDTH{65535};
复制代码
performance_schema.processlist

performance_schema.processlist 表中 INFO 的长度是在pfs_set_thread_info_vc中限制的。
  1. // storage/perfschema/pfs.cc
  2. void pfs_set_thread_info_vc(const char *info, uint info_len) {
  3.   pfs_dirty_state dirty_state;
  4.   PFS_thread *pfs = my_thread_get_THR_PFS();

  5.   if (likely(pfs != nullptr)) {
  6.     if (info_len > sizeof(pfs->m_processlist_info)) {
  7.       info_len = sizeof(pfs->m_processlist_info);
  8.     }
  9.     pfs->m_stmt_lock.allocated_to_dirty(&dirty_state);
  10.     if (info != nullptr && info_len > 0) {
  11.       memcpy(pfs->m_processlist_info, info, info_len);
  12.     }
  13.     pfs->m_processlist_info_length = info_len;
  14.     pfs->m_stmt_lock.dirty_to_allocated(&dirty_state);
  15.   }
  16. }
复制代码
可以看到,INFO 列的最大长度是由 pfs->m_processlist_info 决定的,而 m_processlist_info 是个字符数组,它的最大长度由 COL_INFO_SIZE 决定。
而 COL_INFO_SIZE 又等于 COL_INFO_CHAR_SIZE * 1。其中,COL_INFO_CHAR_SIZE 是一个常量,值为 1024。
  1. // storage/perfschema/pfs_instr.h
  2. char m_processlist_info[COL_INFO_SIZE];

  3. // storage/perfschema/pfs_column_types.h
  4. #define COL_INFO_CHAR_SIZE 1024
  5. /** Size of INFO columns, in bytes. */
  6. #define COL_INFO_SIZE (COL_INFO_CHAR_SIZE * 1)
复制代码
结论


  • 如果查询的是 information_schema.processlist, INFO 列的最大长度是 65535。
  • 如果查询的是 performance_schema.processlist,INFO 列的最大长度是 1024。
  • 如果执行的是SHOW PROCESSLIST,无论 performance_schema_show_processlist 是 ON 还是 OFF, INFO 列的最大长度都是 100。
  • 如果执行的是SHOW FULL PROCESSLIST,

    • 当 performance_schema_show_processlist 等于 OFF 或 MySQL 8.0.22 之前的版本 , INFO 列的最大长度等于 max_allowed_packet。
    • 当 performance_schema_show_processlist 等于 ON 时,INFO 列的最大长度是 1024。


来源:https://www.cnblogs.com/ivictor/p/18251976
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具