Bug #86821 | Trigger allocates memory during SELECT | ||
---|---|---|---|
Submitted: | 26 Jun 2017 4:06 | Modified: | 22 Aug 2024 22:30 |
Reporter: | Charly Batista | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Stored Routines | Severity: | S2 (Serious) |
Version: | 5.6, 5.7 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[26 Jun 2017 4:06]
Charly Batista
[26 Jun 2017 4:07]
Charly Batista
Bash Script to run the test
Attachment: runtest.sh (application/octet-stream, text), 186 bytes.
[26 Jun 2017 4:08]
Charly Batista
SQL File to create tables and trigger
Attachment: create_structure.sql (application/sql, text), 23.48 KiB.
[26 Jun 2017 4:09]
Charly Batista
Stored procedure that inserts data into Table_A
Attachment: create_procedure.sql (application/sql, text), 147.57 KiB.
[26 Jun 2017 4:19]
Charly Batista
The SP helps to test but I've got very similar and consistent results running the plain insert without SP. Running MySQL under valgrind gives more hints: Detailed snapshots: [1, 11, 15, 21, 23, 25 (peak), 27, 39, 43, 56, 66] -------------------------------------------------------------------------------- n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) -------------------------------------------------------------------------------- 0 0 0 0 0 0 1 5,825,620,323 1,846,219,256 1,845,391,654 827,602 0 99.96% (1,845,391,654B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->75.18% (1,387,953,735B) 0xECFAE6: my_malloc (my_malloc.c:191) | ->59.70% (1,102,175,800B) 0xECB92B: alloc_root (my_alloc.c:279) | | ->10.53% (194,367,520B) 0xC2B934: sp_head::reset_lex(THD*) (sql_lex.h:3715) | | | ->04.35% (80,373,728B) 0xDA28FD: MYSQLparse(THD*) (sql_yacc.yy:4108) | | | | ->04.35% (80,373,728B) 0xCB1A62: parse_sql(THD*, Parser_state*, Object_creation_ctx*) (sql_parse.cc:7523) | | | | ->04.35% (80,373,728B) 0xD5C591: Trigger::parse(THD*) (trigger.cc:533) | | | | ->04.35% (80,373,728B) 0xD58036: Table_trigger_dispatcher::parse_triggers(THD*) (table_trigger_dispatcher.cc:689) | | | | ->04.35% (80,373,728B) 0xD581BA: Table_trigger_dispatcher::check_n_load(THD*, bool) (table_trigger_dispatcher.cc:442) | | | | ->04.35% (80,373,728B) 0xC521E5: open_table(THD*, TABLE_LIST*, Open_table_context*) (sql_base.cc:4396) | | | | ->04.35% (80,373,728B) 0xC58650: open_tables(THD*, TABLE_LIST**, unsigned int*, unsigned int, Prelocking_strategy*) (sql_base.cc:5175) | | | | ->04.35% (80,373,728B) 0xC58F69: open_tables_for_query(THD*, TABLE_LIST*, unsigned int) (sql_base.cc:6568) | | | | ->04.35% (80,373,728B) 0xE1F4EB: Sql_cmd_insert::mysql_insert(THD*, TABLE_LIST*) (sql_insert.cc:464) | | | | ->04.35% (80,373,728B) 0xE20370: Sql_cmd_insert::execute(THD*) (sql_insert.cc:3115) | | | | ->04.35% (80,373,728B) 0xCAC1E5: mysql_execute_command(THD*, bool) (sql_parse.cc:3786) | | | | ->04.35% (80,373,728B) 0xC2F57E: sp_instr_stmt::exec_core(THD*, unsigned int*) (sp_instr.cc:1021) | | | | ->04.35% (80,373,728B) 0xC311B2: sp_lex_instr::reset_lex_and_exec_core(THD*, unsigned int*, bool) (sp_instr.cc:412) | | | | ->04.35% (80,373,728B) 0xC31B59: sp_lex_instr::validate_lex_and_execute_core(THD*, unsigned int*, bool) (sp_instr.cc:712) | | | | ->04.35% (80,373,728B) 0xC32ECE: sp_instr_stmt::execute(THD*, unsigned int*) (sp_instr.cc:908) | | | | ->04.35% (80,373,728B) 0xC2AE92: sp_head::execute(THD*, bool) (sp_head.cc:790) | | | | ->04.35% (80,373,728B) 0xC2E935: sp_head::execute_procedure(THD*, List<Item>*) (sp_head.cc:1526) | | | | ->04.35% (80,373,728B) 0xCAF61A: mysql_execute_command(THD*, bool) (sql_parse.cc:4854) | | | | ->04.35% (80,373,728B) 0xCB2353: mysql_parse(THD*, Parser_state*) (sql_parse.cc:5929) | | | | ->04.35% (80,373,728B) 0xCB2E98: dispatch_command(THD*, COM_DATA const*, enum_server_command) (sql_parse.cc:1493) | | | | ->04.35% (80,373,728B) 0xCB48E5: do_command(THD*) (sql_parse.cc:1021) | | | | ->04.35% (80,373,728B) 0xD796AE: handle_connection (connection_handler_per_thread.cc:312) | | | | ->04.35% (80,373,728B) 0x1208A22: pfs_spawn_thread (pfs.cc:2188) | | | | ->04.35% (80,373,728B) 0x4E31A9F: start_thread (in /lib64/libpthread-2.12.so) | | | | ->04.35% (80,373,728B) 0x6B85BCB: clone (in /lib64/libc-2.12.so) <...cut...> Also checking memory events on PS: mysql> select event_name, current_alloc, high_alloc from memory_global_by_current_bytes where current_count > 0; +--------------------------------------------------------------------------------+---------------+-------------+ | event_name | current_alloc | high_alloc | +--------------------------------------------------------------------------------+---------------+-------------+ | memory/innodb/buf_buf_pool | 7.29 GiB | 7.29 GiB | | memory/sql/sp_head::main_mem_root | 3.21 GiB | 3.62 GiB | | memory/innodb/hash0hash | 210.16 MiB | 323.63 MiB | | memory/sql/TABLE | 183.82 MiB | 190.28 MiB | | memory/sql/Query_cache | 128.02 MiB | 128.02 MiB | | memory/mysys/KEY_CACHE | 64.00 MiB | 64.00 MiB | | memory/innodb/log0log | 32.08 MiB | 32.08 MiB | | memory/innodb/parallel_doublewrite | 30.27 MiB | 30.27 MiB | | memory/performance_schema/table_handles | 27.19 MiB | 27.19 MiB | | memory/innodb/mem0mem | 19.14 MiB | 20.79 MiB | | memory/performance_schema/events_statements_history_long | 13.66 MiB | 13.66 MiB | | memory/performance_schema/events_statements_summary_by_digest.tokens | 9.77 MiB | 9.77 MiB | <...cut...> +------+-----------+-----------------------------------------------------+-------------+------------+---------------------------+----------------------- | USER | HOST | EVENT_NAME | COUNT_ALLOC | COUNT_FREE | SUM_NUMBER_OF_BYTES_ALLOC | SUM_NUMBER_OF_BYTES_FREE | +------+-----------+-----------------------------------------------------+-------------+------------+---------------------------+----------------------- | root | localhost | memory/sql/sp_head::main_mem_root | 5161270 | 5123106 | 90436226992 | 89652629360 | | root | localhost | memory/sql/sp_head::main_mem_root | 9857844 | 9840114 | 172671752216 | 172288775328 | | root | localhost | memory/sql/sp_head::main_mem_root | 15116325 | 15077409 | 264845838432 | 263971081760 | | root | localhost | memory/sql/sp_head::main_mem_root | 20147715 | 20108371 | 353006440328 | 352085548776 | | root | localhost | memory/sql/sp_head::main_mem_root | 21860573 | 21822776 | 383022467200 | 382119924096 | | root | localhost | memory/sql/sp_head::main_mem_root | 25300477 | 25260725 | 443310326616 | 442343463704 | | root | localhost | memory/sql/sp_head::main_mem_root | 30462708 | 30441464 | 533762286640 | 533118771504 | | root | localhost | memory/sql/sp_head::main_mem_root | 35595979 | 35574369 | 623717978344 | 623028965448 | <...cut...>
[28 Jun 2017 18:46]
MySQL Verification Team
Hi, Thanks for the bug report. I verified behavior as described. I am not sure this is a bug (I did not detect a memory leak, just memory allocation) but I'll let our dev team look at it further. best regards Bogdan
[10 Jan 2019 17:14]
John LeSueur
I can reproduce on 8.0.13. There's an even simpler test case, and I have some information that I don't know how to interpret. Here's the simple structure that can illustrate the memory growth: CREATE DATABASE `test_sp_head`; DROP TABLE IF EXISTS `test_sp_head`; CREATE TABLE `test_sp_head` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; DELIMITER ;; CREATE TRIGGER `test_sp_head` BEFORE UPDATE ON `test_sp_head` FOR EACH ROW begin signal sqlstate '45000' set message_text = 'triggered'; end ;; DELIMITER ; Then to display the continuous allocation of memory, run this command multiple times: echo "select event_name, current_alloc, high_alloc from sys.memory_global_by_current_bytes where event_name like '%sp_head%'; explain select * from test_sp_head; select event_name, current_alloc, high_alloc from sys.memory_global_by_current_bytes where event_name like '%sp_head%'; " | mysql -A test_sp_head What I see is that for the first 16 connections where we create even a query plan for any table that has triggers associated with it, new memory is allocated. After that memory growth halts. I have learned that mysql parses triggers and stored procedures for each thread/connection, and allocates memory for the compiled version. What I don't know is why that memory is not released when the thread exits, or the connection ends. I'm guessing that there's some pool (though I don't have thread pooling enabled) that is being used for this?
[10 Jan 2019 17:21]
MySQL Verification Team
> > "What I see is that for the first 16 connections" > Tried to tweak table_open_cache_instances to affect this?
[10 Jan 2019 20:22]
John LeSueur
Yes, after changing that, the number of times it caches can be controlled. I had been looking for thread-specific caches, hadn't found that configuration. Thank you! For now, as far as I'm concerned this is not a bug.
[22 Aug 2024 22:30]
Jon Stephens
This is fixed in MySQL 9.1 by BUG#44625 / WL#16455. Closed.