...even surpassing it's theorically maximum possible allocation.
[OK] Maximum possible memory usage: 7.3G (46% of installed RAM)
There is not actually a way to calculate maximum possible memory usage for MySQL, because there is no cap on the memory it can request from the system.
The calculation done by mysqltuner.pl is only an estimate, based on a formula that doesn't take into account all possible variables, because if all possible variables were taken into account, the answer would always be "infinite." It's unfortunate that it's labeled this way.
Here is my theory on what's contributing to your excessive memory usage:
thread_cache_size = 128
Given that your max_connections
is set to 200, the value of 128 for thread_cache_size
seems far too high. Here's what makes me think this might be contributing to your problem:
When a thread is no longer needed, the memory allocated to it is released and returned to the system unless the thread goes back into the thread cache. In that case, the memory remains allocated.
http://dev.mysql.com/doc/refman/5.6/en/memory-use.html
If your workload causes even an occasional client thread to require a large amount of memory, those threads may be holding onto that memory, then going back to the pool and sitting around, continuing to hold on to memory they don't technically "need" any more, on the premise that holding on to the memory is less costly than releasing it if you're likely to need it again.
I think it's worth a try to do the following, after first making a note of how much memory MySQL is using at the moment.
Note how many threads are currently cached:
mysql> show status like 'Threads_cached';
+----------------+-------+
| Variable_name | Value |
+----------------+-------+
| Threads_cached | 9 |
+----------------+-------+
1 row in set (0.00 sec)
Next, disable the thread cache.
mysql> SET GLOBAL thread_cache_size = 0;
This disables the thread cache, but the cached threads will stay in the pool until they're used one more time. Disconnect from the server, then reconnect and repeat.
mysql> show status like 'Threads_cached';
Continue disconnecting, reconnecting, and checking until the counter reaches 0.
Then, see how much memory MySQL is holding.
You may see a decrease, possibly significant, and then again you may not. I tested this on one of my systems, which had 9 threads in the cache. Once those threads had all been cleared out of the cache, the total memory held by MySQL did decrease... not by much, but it does illustrate that threads in the cache do release at least some memory when they are destroyed.
If you see a significant decrease, you may have found your problem. If you don't, then there's one more thing that needs to happen, and how quickly it can happen depends on your environment.
If the theory holds that the other threads -- the ones currently servicing active client connections -- have significant memory allocated to them, either because of recent work in their current client session or because of work requiring a lot of memory that was done by another connection prior to them languishing in the pool, then you won't see all of the potential reduction in memory consumption until those threads are allowed to die and be destroyed. Presumably your application doesn't hold them forever, but how long it will take to know for sure whether there's a difference will depend on whether you have the option of cycling your application (dropping and reconnecting the client threads) or if you'll have to just wait for them to be dropped and reconnected over time on their own.
But... it seems like a worthwhile test. You should not see a substantial performance penalty by setting thread_cache_size
to 0. Fortunately, thread_cache_size
is a dynamic variable, so you can freely change it with the server running.
There is most definitely a difference between SHOW STATUS;
and SHOW GLOBAL STATUS;
SHOW GLOBAL STATUS;
will give you status variables that have updated since mysqld started for all sessions that are connected or have ever been connected.
SHOW STATUS;
will give you status variables that have updated within your session. The command can also be expressed as SHOW SESSION STATUS;
(As the MySQL Documentation says, it displays the status values for the current connection).
To physically show the difference, the information_schema database has them separated as
INFORMATION_SCHEMA.GLOBAL_STATUS
INFORMATION_SCHEMA.SESSION_STATUS
These information_schema tables have been around since MySQL 5.1.12.
Why the difference?
To thoroughly demonstrate the difference, let me run an INNER JOIN of these tables to show which values are different. Here is the query:
SELECT a.variable_name,a.variable_value,b.variable_value
FROM information_schema.global_status A INNER join information_schema.session_status B
USING (variable_name) WHERE A.variable_value <> B.variable_value;
Please note the output:
mysql> SELECT A.variable_name,A.variable_value,B.variable_value
-> FROM information_schema.global_status A INNER join information_schema.session_status B
-> USING (variable_name) WHERE A.variable_value <> B.variable_value;
+---------------------------+----------------+----------------+
| variable_name | variable_value | variable_value |
+---------------------------+----------------+----------------+
| BYTES_RECEIVED | 123641576598 | 7757 |
| BYTES_SENT | 149888451047 | 300001 |
| COM_ADMIN_COMMANDS | 121915 | 0 |
| COM_ALTER_TABLE | 111 | 0 |
| COM_BEGIN | 1 | 0 |
| COM_CALL_PROCEDURE | 530 | 0 |
| COM_CHANGE_DB | 1623 | 1 |
| COM_COMMIT | 19220 | 0 |
| COM_CREATE_FUNCTION | 4 | 0 |
| COM_CREATE_PROCEDURE | 126 | 0 |
| COM_CREATE_TABLE | 354 | 0 |
| COM_DEALLOC_SQL | 924 | 0 |
| COM_DELETE | 64668 | 0 |
| COM_DELETE_MULTI | 19 | 0 |
| COM_DROP_FUNCTION | 4 | 0 |
| COM_DROP_PROCEDURE | 148 | 0 |
| COM_DROP_TABLE | 238 | 0 |
| COM_EXECUTE_SQL | 945 | 0 |
| COM_INSERT | 1182379 | 0 |
| COM_INSERT_SELECT | 40673 | 0 |
| COM_KILL | 68 | 0 |
| COM_LOAD | 22386 | 0 |
| COM_LOCK_TABLES | 2 | 0 |
| COM_OPTIMIZE | 2 | 0 |
| COM_PREPARE_SQL | 948 | 0 |
| COM_REPAIR | 8 | 0 |
| COM_REPLACE | 34737 | 0 |
| COM_ROLLBACK | 13 | 0 |
| COM_SELECT | 1107225018 | 65 |
| COM_SET_OPTION | 602159 | 0 |
| COM_SHOW_BINLOGS | 8 | 0 |
| COM_SHOW_CHARSETS | 12 | 0 |
| COM_SHOW_COLLATIONS | 100 | 0 |
| COM_SHOW_CREATE_DB | 6 | 0 |
| COM_SHOW_CREATE_FUNC | 2453 | 0 |
| COM_SHOW_CREATE_PROC | 5684 | 0 |
| COM_SHOW_CREATE_TABLE | 1313 | 0 |
| COM_SHOW_DATABASES | 275 | 0 |
| COM_SHOW_EVENTS | 1 | 0 |
| COM_SHOW_FIELDS | 13666 | 1 |
| COM_SHOW_FUNCTION_STATUS | 362 | 0 |
| COM_SHOW_KEYS | 494 | 0 |
| COM_SHOW_PLUGINS | 2 | 0 |
| COM_SHOW_PROCEDURE_STATUS | 361 | 0 |
| COM_SHOW_PROCESSLIST | 488943 | 15 |
| COM_SHOW_SLAVE_STATUS | 4 | 0 |
| COM_SHOW_STATUS | 12315 | 10 |
| COM_SHOW_STORAGE_ENGINES | 30 | 0 |
| COM_SHOW_TABLE_STATUS | 320 | 0 |
| COM_SHOW_TABLES | 584 | 0 |
| COM_SHOW_TRIGGERS | 2 | 0 |
| COM_SHOW_VARIABLES | 190 | 1 |
| COM_STMT_CLOSE | 924 | 0 |
| COM_STMT_EXECUTE | 945 | 0 |
| COM_STMT_PREPARE | 948 | 0 |
| COM_TRUNCATE | 522 | 0 |
| COM_UNLOCK_TABLES | 2 | 0 |
| COM_UPDATE | 496041 | 0 |
| COM_UPDATE_MULTI | 625 | 0 |
| CREATED_TMP_DISK_TABLES | 16772 | 40 |
| CREATED_TMP_TABLES | 34336 | 63 |
| HANDLER_COMMIT | 1109540769 | 0 |
| HANDLER_DELETE | 12775993 | 0 |
| HANDLER_EXTERNAL_LOCK | 2228108102 | 24 |
| HANDLER_PREPARE | 2155764 | 0 |
| HANDLER_READ_FIRST | 23586 | 9 |
| HANDLER_READ_KEY | 18285349400 | 0 |
| HANDLER_READ_LAST | 13000 | 0 |
| HANDLER_READ_NEXT | 72142303428 | 0 |
| HANDLER_READ_PREV | 3000146 | 0 |
| HANDLER_READ_RND | 1261418742 | 156 |
| HANDLER_READ_RND_NEXT | 12320861765 | 7845 |
| HANDLER_ROLLBACK | 269376 | 0 |
| HANDLER_UPDATE | 2596924399 | 0 |
| HANDLER_WRITE | 8200421074 | 8241 |
| LAST_QUERY_COST | 0.000000 | 21.399123 |
| LAST_QUERY_PARTIAL_PLANS | 0 | 3 |
| OPENED_TABLE_DEFINITIONS | 2482 | 0 |
| OPENED_TABLES | 3619 | 0 |
| QUESTIONS | 1110214247 | 97 |
| SELECT_FULL_JOIN | 615 | 9 |
| SELECT_RANGE | 243635 | 0 |
| SELECT_SCAN | 47851 | 53 |
| SLOW_QUERIES | 29290 | 50 |
| SORT_MERGE_PASSES | 6 | 0 |
| SORT_RANGE | 179956 | 0 |
| SORT_ROWS | 321609927 | 156 |
| SORT_SCAN | 1829 | 39 |
| TABLE_OPEN_CACHE_HITS | 1109365721 | 13 |
| TABLE_OPEN_CACHE_MISSES | 1669 | 0 |
+---------------------------+----------------+----------------+
90 rows in set (0.03 sec)
mysql>
Look at four variables:
| BYTES_RECEIVED | 123641576598 | 7757 |
| BYTES_SENT | 149888451047 | 300001 |
| COM_ADMIN_COMMANDS | 121915 | 0 |
| COM_SHOW_PROCESSLIST | 488955 | 15 |
What does this tell you?
- mysqld received 123,641,576,598 bytes (115.15GB) from all DB Connections since mysqld started
- The session I ran the query with received 7,757 bytes (a little over 7K) in my current session
- mysqld sent 149,888,451,047 bytes (139.59GB) from all DB Connections since mysqld started
- The session I ran the query with sent 300,001 bytes (a little under 297K) in my current session
- There have been 121,915 administrative commands that have run since mysqld started
- There have benn 0 administrative commands that have run in my current session
- The command
SHOW PROCESSLIST
has been run 488,955 times since mysqld started
- The command
SHOW PROCESSLIST
has been run 15 times in my current session
You can compare the other 86 varibales and interpret them the same way.
Give it a Try !!!
Best Answer
To use least amount of QC space, use
for less waste of QC RAM and qcache_lowmem_prunes expected to decrease as well over time.