{"id":106364,"date":"2025-05-15T06:54:00","date_gmt":"2025-05-15T06:54:00","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=106364"},"modified":"2025-08-04T07:27:06","modified_gmt":"2025-08-04T07:27:06","slug":"mysql-shell-basic-configuration-management-part-4-optimizing-mysql-performance","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/mysql-shell-basic-configuration-management-part-4-optimizing-mysql-performance\/","title":{"rendered":"MySQL Shell Basic Configuration Management (Part 4 &#8211; Optimizing MySQL Performance)"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\" id=\"h-\"><\/h1>\n\n\n\n<p>Welcome back to our journey of understanding MySQL performance tuning using MySQL Shell. So far, we\u2019ve covered essential topics like <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/part-i-introduction-to-mysql-shell-and-basic-configuration-management\/\">configuring MySQL<\/a>, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/memory-and-cpu-configuration-using-mysql-shell\/\">optimizing memory and CPU usage<\/a>, and <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/mysql-shell-basic-configuration-management-part-3-disk-i-o-and-storage-optimization\/\">enhancing disk I\/O performance<\/a>. These are important building blocks to ensure your MySQL server is running smoothly. Now, in this fourth part of the series, we will focus on network and query performance optimization.<\/p>\n\n\n\n<p>Network settings and query performance have a significant impact on the overall performance of your MySQL server. In this article, we\u2019ll see how we can use MySQL Shell to check and fine-tune settings in these areas for better performance. We\u2019ll look at adjusting important network parameters, identifying and optimizing slow queries, and configuring the query cache, all within MySQL Shell. Whether you&#8217;re running a small database for an app or managing an enterprise-scale system, network and query optimization will help ensure your MySQL server remains fast and responsive.<\/p>\n\n\n\n<p>When you think about database optimization, you probably picture speeding up queries or improving server response times. Both of these things are heavily influenced by how well MySQL handles network traffic and how efficiently it executes queries. If you have slow queries or network-related bottlenecks, even the most optimized server won\u2019t perform as well as it should. That\u2019s why network and query tuning is an important part of database performance.<\/p>\n\n\n\n<p>MySQL Shell makes this process easier by giving us the tools to adjust network settings, monitor queries, and configure caching. With Shell scripting, we can create reusable scripts and also automate many of these tasks, making MySQL Shell an ideal tool for this job, especially if you do a lot of your management from the command line.<\/p>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\"><em>As mentioned <\/em><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/mysql-shell-basic-configuration-management-part-3-disk-i-o-and-storage-optimization\/\"><em>earlier in the series<\/em><\/a><em>, many of these commands can be simply executed as SQL statements, but we are doing this to build up a set of MySQL Shell commands that can be used to manage your MySQL environment.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-configuring-network-related-parameters-with-mysql-shell\"><a id=\"post-106364-_heading=h.c138h1yui7x\"><\/a>Configuring Network-Related Parameters with MySQL Shell<\/h2>\n\n\n\n<p>Network settings control how MySQL handles communication between clients and the server. If these settings are misconfigured, your server may struggle to handle a large number of connections, or it might drop connections altogether when traffic increases. Thankfully, we can check and tweak these settings using MySQL Shell.<\/p>\n\n\n\n<p>Let\u2019s start by looking at some network parameters, such as <code>max_allowed_packet<\/code>, which determines the maximum size of a packet that the server can handle. If this value is too small, large queries or data transfers might fail. Here\u2019s how we can check and modify this value in MySQL Shell.<\/p>\n\n\n\n<p>First, connect to your MySQL server and switch to JavaScript mode:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">mysqlsh --uri root@localhost\n\n\\js<\/pre><\/div>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\"><em>Note: If you need to enter a password, you\u2019ll be prompted. If you\u2019re unsure about connection details, please refer back to <\/em><a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/part-i-introduction-to-mysql-shell-and-basic-configuration-management\/\"><em>Part 1 of this series<\/em><\/a><em>. And as a reminder that this will connect with the very powerful root user, so be careful doing this on a production server if you are not sure what you are doing.<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-max-allowed-packet\">Max_allowed_packet<\/h3>\n\n\n\n<p><code>max_allowed_packet<\/code>, which sets the packet size that MySQL uses to communicate with your clients by default:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">var result = session.runSql('SHOW VARIABLES LIKE \"max_allowed_packet\"');\n\nprint(\"Current max_allowed_packet: \" + result.fetchOne()[1] + \" bytes\");<\/pre><\/div>\n\n\n\n<p>You\u2019ll see the current size of the max_allowed_packet. For example, if it shows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"34\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-1.png\" alt=\"\" class=\"wp-image-106365\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-1.png 512w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-1-300x20.png 300w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>This value is 6 MB. If your server handles large data sets, especially using long strings or <code>BLOB<\/code> columns, this might be too low. You can increase it to 16 MB or even higher, depending on your workload. Let\u2019s adjust it to 16 MB .<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">let maxAllowedPacket = 16777216;\n\nsession.runSql(`SET GLOBAL max_allowed_packet = ${maxAllowedPacket}`);\n\nprint(`max_allowed_packet updated to ${maxAllowedPacket} bytes (${maxAllowedPacketMB} MB).`);<\/pre><\/div>\n\n\n\n<p>The <code>SET GLOBAL<\/code> command will make the change for all new connections to the server. This means that if you execute the <code>SHOW VARIABLES<\/code> command in the same connection in a query tool, without reconnecting, the setting will not show as changed. Any new connection will get the new <code>max_allowed_packet<\/code> setting.<\/p>\n\n\n\n<p>Note too that these changes will not be permanent, in that when you restart the server, they will not be remembered. If you want to make a permanent change, you need to change the value on startup or in the configuration file. For more details, check the documentation on <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/server-system-variables.html\">setting system variable values<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-net-read-timeout\">net_read_timeout<\/h3>\n\n\n\n<p>Another important network setting is <code>net_read_timeout<\/code>, which determines how long the server waits to read data from the network before timing out. If your server deals with long-running queries or large data transfers, increasing this value can help avoid timeouts. Check the current value like this:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result = session.runSql('SHOW VARIABLES LIKE \"net_read_timeout\"');\n\nprint(\"Current net_read_timeout: \" + result.fetchOne()[1] + \" seconds\");<\/pre><\/div>\n\n\n\n<p>The output should be similar to this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"569\" height=\"82\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-2.png\" alt=\"\" class=\"wp-image-106366\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-2.png 569w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-2-300x43.png 300w\" sizes=\"auto, (max-width: 569px) 100vw, 569px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>Let\u2019s increase the timeout to 120 seconds to handle cases where slower connections aren\u2019t reading the data in the 30 seconds:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">\/\/ Assign the desired time to a variable\nlet netReadTimeout = 120;\n\n\/\/ Use the variable in your SQL command\nsession.runSql(`SET GLOBAL net_read_timeout = ${netReadTimeout}`);\n\nprint(`net_read_timeout updated to ${netReadTimeout} seconds.`);<\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"393\" height=\"26\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-3.png\" alt=\"\" class=\"wp-image-106367\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-3.png 393w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-3-300x20.png 300w\" sizes=\"auto, (max-width: 393px) 100vw, 393px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>Once you\u2019ve made these changes, MySQL will be better equipped to handle large queries and long-running connections without dropping them until the server is restarted.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-monitoring-and-tuning-connections-and-throughput-with-shell-scripting\"><a id=\"post-106364-_heading=h.v8ni1muzyi4b\"><\/a>Monitoring and Tuning Connections and Throughput with Shell Scripting<\/h2>\n\n\n\n<p>After modifying these network parameters, it\u2019s important to monitor how well your server is handling connections and network traffic. We can use MySQL Shell to keep an eye on the number of active connections and adjust the connection settings if necessary.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-threads-connected\">Threads_connected<\/h3>\n\n\n\n<p>To check the current number of connections (also referred to as threads in MySQL), use the following command in MySQL Shell:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result = session.runSql('SHOW GLOBAL STATUS LIKE \"Threads_connected\"');\n\nprint(\"Current connections: \" + result.fetchOne()[1]);<\/pre><\/div>\n\n\n\n<p>You\u2019ll see how many client connections are currently active. There are a few other similar values you can query such as <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/server-status-variables.html#statvar_Threads_created\">Threads_created<\/a> and <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/server-status-variables.html#statvar_Threads_running\">Threads_running<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-max-connections\">Max Connections<\/h3>\n\n\n\n<p>If your server handles many connections, you might need to increase the <code>max_connections<\/code> parameter to prevent connection issues during traffic spikes. Here\u2019s how you can check and update the <code>max_connections<\/code> setting:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result = session.runSql('SHOW VARIABLES LIKE \"max_connections\"');\n\nprint(\"Current max_connections: \" + result.fetchOne()[1]);<\/pre><\/div>\n\n\n\n<p>And if you need to make a change, you can use the following code:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">\/\/ Assign the desired time to a variable\nlet maxConnections = 500;\n\n\/\/ Use the variable in your SQL command\nsession.runSql(`SET GLOBAL max_connections = ${maxConnections}`);\n\nprint(`max_connections updated to ${maxConnections}.`);<\/pre><\/div>\n\n\n\n<p>By increasing <code>max_connections<\/code>, your server will be able to handle up to 500 connections simultaneously, making it more robust during peak traffic times. Note of course, you need to make sure that your server can handle the larger number of connections. Just increasing this value higher and higher could lead to other resource issues, making the connected users experience poorer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-query-cache-and-execution-plans-using-mysql-shell\"><a id=\"post-106364-_heading=h.8mqnyk97gphm\"><\/a>Query Cache and Execution Plans Using MySQL Shell<\/h2>\n\n\n\n<p>Now that we\u2019ve tuned the network settings, let\u2019s focus on query optimization, which is where MySQL performance often falters. While you could use tools like MySQL Workbench or DBeaver for this, MySQL Shell offers some advantages for repeatability. We can create reusable functions that help us identify, analyze, and optimize slow queries in a systematic way.<\/p>\n\n\n\n<p>The first step in query optimization is understanding how MySQL executes your queries. MySQL provides the <code>EXPLAIN<\/code> statement, which shows the execution plan for a given query. You can use this tool directly in MySQL Shell to analyze and improve query performance. In addition to analyzing queries, MySQL Shell can help us identify slow queries. We can check the slow query log to see which queries are taking the longest to execute. Let\u2019s check the <code>long_query_time<\/code> setting to see how long a query must take before it\u2019s logged as slow:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result = session.runSql('SHOW VARIABLES LIKE \"long_query_time\"');\n\nprint(\"Current long_query_time: \" + result.fetchOne()[1] + \" seconds\");<\/pre><\/div>\n\n\n\n<p>The output will be similar to the following:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"365\" height=\"86\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-4.png\" alt=\"\" class=\"wp-image-106368\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-4.png 365w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-4-300x71.png 300w\" sizes=\"auto, (max-width: 365px) 100vw, 365px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>If we want to log queries that take more than 2 seconds, we can adjust this setting with the following code:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">\/\/ Assign the desired time to a variable\nlet longQueryTime = 2;\n\n\/\/ Use the variable in your SQL command\nsession.runSql(`SET GLOBAL long_query_time = ${longQueryTime}`);\n\nprint(`long_query_time updated to ${longQueryTime} seconds.`);<\/pre><\/div>\n\n\n\n<p>Once this is set, you can check the slow query log to find the slowest queries and start optimizing them using <code>EXPLAIN<\/code>. When a MySQL server begins to slow down, the first question to ask is: which queries are causing the delay?<\/p>\n\n\n\n<p>Jumping straight to optimization techniques without answering that is often counterproductive. Before using <code>EXPLAIN<\/code> or modifying server settings, the process must begin by identifying the problematic queries.<\/p>\n\n\n\n<p>You can enable the slow query log with the following SQL statements:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">\/\/ Define your parameters\nlet slowQueryLog = 'ON';\nlet longQueryTime = 2;\n\n\/\/ Use the variables in your SQL statements\nsession.sql(`SET GLOBAL slow_query_log = '${slowQueryLog}'`).execute();\n\nprint(`slow_query_log updated to '${slowQueryLog}'.`);\n\nsession.sql(`SET GLOBAL long_query_time = ${longQueryTime}`).execute();\n\nprint(`long_query_time updated to ${longQueryTime} seconds.`);<\/pre><\/div>\n\n\n\n<p>The first command enables the logging of slow queries, while the second sets the threshold for what MySQL should consider a &#8220;slow&#8221; query. In this example, any query that takes longer than 2 seconds will be logged.<\/p>\n\n\n\n<p>You can confirm that the slow query log is active by running:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.sql(\"SHOW VARIABLES LIKE 'slow_query_log'\").execute().fetchAll();<\/pre><\/div>\n\n\n\n<p>Once confirmed, you can also check where the log file is stored on your server:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.sql(\"SHOW VARIABLES LIKE'slow_query_log_file'\").execute().fetchAll();<\/pre><\/div>\n\n\n\n<p>It shows the file path where MySQL is storing the slow queries. You can open this log file to review the entries.<\/p>\n\n\n\n<p>Once a problematic query has been identified, the next step is to use the EXPLAIN statement to understand how MySQL executes it. For example:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.sql(\"EXPLAIN SELECT * FROM products WHERE category = 'electronics'\").execute().fetchAll();<\/pre><\/div>\n\n\n\n<p>If the output shows <code>`type: ALL`<\/code> it indicates a full table scan, meaning MySQL must inspect every row in the products table, `<code>possible_keys<\/code>` being <code>`NULL`<\/code> suggests there is no index available to make the query faster. `rows` shows the number of rows the server had to scan to resolve the query. This kind of pattern shows that creating an index on the category column will likely improve performance.<\/p>\n\n\n\n<p>After adding the index:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.sql(\"ALTER TABLE products ADD INDEX idx_category(category)\").execute();<\/pre><\/div>\n\n\n\n<p>If you rerun <code>EXPLAIN<\/code>, <code>`type:ref`<\/code>will indicate the query is using the index instead of scanning the full table, <code>`key: idx_category`<\/code> confirms that the new index is in use, and `rows` shows that MySQL now needs to check fewer rows compared to before, which is a significant improvement.<\/p>\n\n\n\n<p>Aside from log analysis, you can catch slow queries in real time using the <code>`SHOW FULL PROCESSLIST`<\/code> command.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.sql(\"SHOW FULL PROCESSLIST\").execute().fetchAll();<\/pre><\/div>\n\n\n\n<p>This command returns a snapshot of all running threads and their current states. The <code>`Time`<\/code> column shows how many seconds the query has been running; the Command column shows the type of operation. Query means it\u2019s executing a statement. If a query shows a high time value, it may be worth investigating further.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-fine-tuning-join-and-sorting-algorithms-with-mysql-shell\"><a id=\"post-106364-_heading=h.2euhclclly3k\"><\/a>Fine-Tuning Join and Sorting Algorithms with MySQL Shell<\/h2>\n\n\n\n<p>Complex queries that involve JOINs or SORTs can be performance killers if not optimized properly. MySQL Shell allows us to adjust the size of join buffers and sort buffers, which can improve the performance of these operations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-viewing-the-settings\">Viewing the settings<\/h3>\n\n\n\n<p>Let\u2019s check the current <code>join_buffer_size<\/code> and <code>sort_buffer_size<\/code> settings:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result = session.runSql('SHOW VARIABLES LIKE \"join_buffer_size\"');\nprint(\"Current join_buffer_size: \" + result.fetchOne()[1] + \" bytes\");\n\nresult = session.runSql('SHOW VARIABLES LIKE \"sort_buffer_size\"');\nprint(\"Current sort_buffer_size: \" + result.fetchOne()[1] + \" bytes\");<\/pre><\/div>\n\n\n\n<p>The outputs will be similar to:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"265\" height=\"86\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-5.png\" alt=\"\" class=\"wp-image-106369\"\/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"230\" height=\"86\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-6.png\" alt=\"\" class=\"wp-image-106370\"\/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-changing-the-settings\">Changing the settings<\/h3>\n\n\n\n<p>When optimizing MySQL performance, adjusting buffer sizes like <code>`join_buffer_size`<\/code> and <code>`sort_buffer_size`<\/code> can be beneficial, but it\u2019s essential to understand when and why these changes should be made. The <code>`join_buffer_size`<\/code> is used to set the buffer for join operations, while the <code>`sort_buffer_size`<\/code> is used for sorting.<\/p>\n\n\n\n<p>If these buffers are too small, MySQL may need to perform disk I\/O for operations that could be handled in memory, which can significantly slow down query performance. Increasing the buffer sizes allows MySQL to perform these operations more efficiently in memory, reducing the need for slower disk-based operations. But of course, setting them higher can use memory unnecessarily, and squeeze other processes need RAM.<\/p>\n\n\n\n<p>Before blindly increasing these buffer sizes, you must first evaluate if it is necessary. You can use the following commands to check the current values for <code>`join_buffer_size`<\/code> and <code>`sort_buffer_size`<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">var joinBuffer = session.runSql(\"SHOW VARIABLES LIKE 'join_buffer_size';\");\nvar sortBuffer = session.runSql(\"SHOW VARIABLES LIKE 'sort_buffer_size';\");\n\nprint(joinBuffer);\nprint(sortBuffer);<\/pre><\/div>\n\n\n\n<p>The output will show the current buffer sizes. If the current values are too small for the queries you&#8217;re running, you might consider increasing them.<\/p>\n\n\n\n<p>If your server has enough memory available, increasing the buffer sizes could help with performance. However, if your server is running low on memory or handling many simultaneous connections, increasing the buffer sizes too much can lead to excessive memory consumption, causing your system to slow down or crash.<\/p>\n\n\n\n<p>Use this command to check if your server is reading a lot of data from disk instead of using the buffer:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">var bufferReads = session.runSql(\"SHOW STATUS LIKE 'Innodb_buffer_pool_reads';\");\n\nprint(bufferReads);<\/pre><\/div>\n\n\n\n<p>If this value is high, it indicates that your server is doing a lot of disk reads, which means your buffers might be too small, and increasing them could help.<\/p>\n\n\n\n<p>Once you\u2019ve determined that increasing the buffer sizes would benefit your queries, you can adjust them like this (I will leave it to you to add variables for this script if you wish):<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.runSql('SET GLOBAL join_buffer_size = 8388608');  \/\/ 8MB\nsession.runSql('SET GLOBAL sort_buffer_size = 8388608');  \/\/ 8MB\n\nprint(\"join_buffer_size and sort_buffer_size updated to 8MB.\");\n<\/pre><\/div>\n\n\n\n<p><strong>Note<\/strong>: These changes are applied globally, so be cautious when adjusting them in a production environment. It\u2019s always a good idea to test these changes on a staging server first. It is important not to blindly change buffer sizes without first analyzing whether they are the cause of performance issues. Monitoring query performance, checking the current buffer sizes, and ensuring your server has enough memory are essential steps before adjusting these settings. Only increase these settings when you are sure that the buffer size is limiting performance due to large joins or sorts. It makes it clear that buffer changes should be a solution to a problem, not a default action.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-monitoring-the-effects\"><a id=\"post-106364-_heading=h.dxwprxqxg0px\"><\/a>Monitoring the effects<\/h3>\n\n\n\n<p>To monitor the performance of queries using these buffers, we can enable profiling in MySQL Shell. Here\u2019s how to enable profiling and view the performance of a specific query:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.runSql('SET profiling = 1');\nsession.runSql('SELECT * FROM products ORDER BY name');\n\nresult = session.runSql('SHOW PROFILE FOR QUERY 1');\n\nvar row;\nwhile (row = result.fetchOne()) {\n    print(row);\n}<\/pre><\/div>\n\n\n\n<p>You will see something similar to:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"244\" height=\"126\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/04\/word-image-106364-7.png\" alt=\"\" class=\"wp-image-106371\"\/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>This will show the amount of time each part of the query took to execute, helping you identify issues in the query execution process.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-using-mysql-shell-for-prepared-statements-and-query-caching\"><a id=\"post-106364-_heading=h.gfb0i5fpf6eb\"><\/a>Using MySQL Shell for Prepared Statements and Query Caching<\/h2>\n\n\n\n<p>Prepared statements can improve query performance by allowing MySQL to precompile the query, avoiding the overhead of reparsing and optimizing it every time. Let\u2019s look at how we can use prepared statements in MySQL Shell.<\/p>\n\n\n\n<p>First, prepare the statement:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.runSql('PREPARE ProductStmt FROM \"SELECT * FROM products WHERE category = ?\"');\n\nprint(\"Prepared statement created.\");<\/pre><\/div>\n\n\n\n<p>Next, we can execute the prepared statement with different parameters, which will execute faster than a standard query because MySQL only needs to parse, check syntax, and generate an execution plan once when the statement is prepared. After that, MySQL just plugs in the new parameter and runs the precompiled plan. This saves time, especially when the same query structure is reused many times in a loop or high-traffic scenario. In contrast, a regular query forces MySQL to repeat the parsing and planning for every execution, even if only the parameter changes:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.runSql('EXECUTE ProductStmt USING \"Electronics\"');\n\nsession.runSql('EXECUTE ProductStmt USING \"Clothing\"');<\/pre><\/div>\n\n\n\n<p>Query caching can also improve performance by storing the results of frequently executed queries. To check if query caching is enabled, run:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result = session.runSql('SHOW VARIABLES LIKE \"query_cache_type\"');\n\nprint(\"Query cache type: \" + result.fetchOne()[1]);<\/pre><\/div>\n\n\n\n<p>If query caching is enabled, MySQL will automatically store the result of any eligible query. When the exact same query is executed again, with the same text and the same database state, MySQL will return the cached result instantly, which saves the time it would normally take to parse, plan, and execute the query. However, when you update, insert, or delete data in a table, MySQL invalidates any cached results for that table. This is done to avoid returning outdated information.<\/p>\n\n\n\n<p>That\u2019s why query caching isn\u2019t always helpful in databases that are frequently updated \u2014 if the underlying data changes often, the cache is constantly being cleared and rebuilt, which limits the benefit. Query caching is usually most effective in systems where the data is mostly read-only or where changes happen infrequently.<\/p>\n\n\n\n<p>To disable query caching, run:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">session.runSql('SET GLOBAL query_cache_type = OFF');\n\nprint(\"Query cache disabled.\");<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-monitoring-network-and-query-performance-using-mysql-shell\"><a id=\"post-106364-_heading=h.bo2i6d6h8jac\"><\/a>Monitoring Network and Query Performance Using MySQL Shell<\/h2>\n\n\n\n<p>Once you\u2019ve made these optimizations, it\u2019s important to monitor the network and query performance to ensure your changes are effective. You can use MySQL Shell to monitor active queries and check for network latency.<\/p>\n\n\n\n<p>To monitor active queries, run:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result = session.runSql('SHOW FULL PROCESSLIST');\n\nvar row;\nwhile (row = result.fetchOne()) {\n    print(row);\n}<\/pre><\/div>\n\n\n\n<p>This script will send a simple <code>`SELECT 1`<\/code> query to the MySQL server every 5 seconds. If the server responds successfully, it will print a message along with the exact time the response was received.<\/p>\n\n\n\n<p>When you run the script, it shows if the server is reachable and responding. If there\u2019s a delay or connection problem, the time between messages will increase, or you\u2019ll stop seeing the messages altogether.<\/p>\n\n\n\n<p>To check network latency, we can use a Shell script to periodically ping the MySQL server and log the response times:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">function monitorLatency() {\n    var result;\n    var startTime, endTime, duration;\n    while (true) {\n        startTime = new Date();\n        result = session.runSql('SELECT 1');\n        result.fetchOne();  \/\/ Make sure the server returns the result\n        endTime = new Date();\n        duration = endTime - startTime;\n        print(\"Ping successful. Response time: \" + duration + \" ms at \" + endTime);\n        shell.sleep(5);\n    }\n}\nmonitorLatency();<\/pre><\/div>\n\n\n\n<p>This way, the script not only confirms the server is up but also tells you the round-trip time for the query, which reflects both the network latency and the server\u2019s responsiveness. If the numbers start climbing, that\u2019s a strong sign of latency or network congestion.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\"><a id=\"post-106364-_heading=h.ye47di6tjbay\"><\/a>Conclusion<\/h2>\n\n\n\n<p>In this article, we\u2019ve looked at how to optimize network and query performance using MySQL Shell. By fine-tuning network settings, optimizing query execution plans, and monitoring query performance, we can ensure that our MySQL server remains responsive and efficient.<\/p>\n\n\n\n<p>In the next and final part of this series, we\u2019ll go into automating performance optimization using some features in MySQL Shell. We\u2019ll look at creating automated scripts for regular maintenance, ensuring that your server stays optimized without manual intervention. The key is to understand your workload, monitor performance regularly, and make incremental improvements.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Welcome back to our journey of understanding MySQL performance tuning using MySQL Shell. So far, we\u2019ve covered essential topics like configuring MySQL, optimizing memory and CPU usage, and enhancing disk I\/O performance. These are important building blocks to ensure your MySQL server is running smoothly. Now, in this fourth part of the series, we will&#8230;&hellip;<\/p>\n","protected":false},"author":342096,"featured_media":106373,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,145792],"tags":[159266,5854],"coauthors":[159002],"class_list":["post-106364","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-featured","category-mysql","tag-chisomkanu_mysqlshell","tag-mysql"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106364","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/342096"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=106364"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106364\/revisions"}],"predecessor-version":[{"id":106372,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106364\/revisions\/106372"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/106373"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=106364"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=106364"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=106364"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=106364"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}