Friday, May 3, 2013

How to tune the MySQL Server

This blog post is part of blog series
    To continue now with the server itself:

    Well besides just saying do what Peter says, lets review examples of how they can solve this themselves.

    For starters, you can compare you my.cnf file against the Q&A version that is available for free via Percona.  It this an ideal solution? No, but it will allow you to take a fresh look at your configuration file after you answers all of their questions, via their configuration wizard.


    innodb_buffer_pool_size
    select @@innodb_buffer_pool_size;

    Setting the innodb_buffer_pool_size is by far one of the most important settings for a MySQL InnoDB database.Some good reading on this topic is below:
    You need to keep in mind that there is not a "one size fits all query" for setting the innodb_buffer_pool_size.  We do have some common guidelines and suggestions that have surfaced over the years (seen below) and we also have several different theories about the best options.

    SELECT CEILING(Total_InnoDB_Bytes*1.6/POWER(1024,3)) RIBPS
    FROM (SELECT SUM(data_length+index_length) Total_InnoDB_Bytes
    FROM information_schema.tables WHERE engine='InnoDB') A;


    SELECT CONCAT(ROUND(KBS/POWER(1024,
    IF(PowerOf1024<0,0,IF(PowerOf1024>3,0,PowerOf1024)))+0.49999),
    SUBSTR(' KMG',IF(PowerOf1024<0,0,
    IF(PowerOf1024>3,0,PowerOf1024))+1,1)) recommended_innodb_buffer_pool_size
    FROM (SELECT SUM(data_length+index_length) KBS FROM information_schema.tables
    WHERE engine='InnoDB') A,
    (SELECT 3 PowerOf1024) B;

    It is safe to say that if you have the default 8M set as your innodb_buffer_pool_size  variable then this should be one of the first settings you adjust.

    Basically, allow this to have all of the available memory you can afford to give it. This of course takes into account several factors, like what else needs to allocate memory on the server ?  Keep in mind that Disk I/O is important to performance and the more memory you allow this variable to have the less disk I/O  should be required for table access.

    Let us also consider this....
    Since a general recommendation is to set the innodb_log_file_size at  25 % of the buffer pool size we should evaluate what we have for the innodb_log_file_size per Baron's concepts then look to see how the relates to the innodb_buffer_pool_size.

    For example, following the logic from Baron's post:
    > show engine innodb status\G select sleep(60); show engine innodb status\G
    Log sequence number 3982683217
    1 row in set (0.01 sec)

    1 row in set (59.99 sec)

    Log sequence number 3991367755
    1 row in set (0.01 sec)

    > SET @sequence1=3982683217;
    Query OK, 0 rows affected (0.00 sec)
    > SET @sequence2=3991367755;
    Query OK, 0 rows affected (0.00 sec)
    > select (@sequence2 - @sequence1) / 1024 / 1024 as MB_per_min;
    +------------+
    | MB_per_min |
    +------------+
    | 8.28222084 |
    +------------+
    1 row in set (0.00 sec)
    > select ( (@sequence2 - @sequence1) / 1024 / 1024 )* 60 as MB_per_hour ;
    +--------------+
    | MB_per_hour  |
    +--------------+
    | 496.93325043 |
    +--------------+
    1 row in set (0.00 sec)
    > select ( ( (@sequence2 - @sequence1) / 1024 / 1024 )* 60 ) * 4 as estimated_buffer_pool ;
    +-----------------------+
    | estimated_buffer_pool |
    +-----------------------+
    |         1987.73300171 |
    +-----------------------+
    1 row in set (0.00 sec)
    > select ( ( ( (@sequence2 - @sequence1) / 1024 / 1024 )* 60 ) * 4 ) / 1024 as estimated_buffer_pool_GB ;
    +--------------------------+
    | estimated_buffer_pool_GB |
    +--------------------------+
    |           1.941145509481 |
    +--------------------------+
    1 row in set (0.00 sec)

    Now when you compare these results to the "guidelines"
    SELECT CONCAT(ROUND(KBS/POWER(1024,
        -> IF(PowerOf1024<0,0,IF(PowerOf1024>3,0,PowerOf1024)))+0.49999),
        -> SUBSTR(' KMG',IF(PowerOf1024<0,0,
        -> IF(PowerOf1024>3,0,PowerOf1024))+1,1)) recommended_innodb_buffer_pool_size
        -> FROM (SELECT SUM(data_length+index_length) KBS FROM information_schema.tables
        -> WHERE engine='InnoDB') A,
        -> (SELECT 3 PowerOf1024) B;
    +-------------------------------------+
    | recommended_innodb_buffer_pool_size |
    +-------------------------------------+
    | 1G                                  |
    +-------------------------------------+

    You get a different result.   While Baron's check is dependent on the time frame it is executed within (which is why you should check this during peak traffic)  it can give you a more realistic view on YOUR traffic and use.  I would look into setting the  innodb_buffer_pool_size to 2G not 1G in this simple example.

    SET @sequence1=3982683217;
    SET @sequence2=3991367755;
    select (@sequence2 - @sequence1) / 1024 / 1024 as MB_per_min;
    select ( (@sequence2 - @sequence1) / 1024 / 1024 )* 60 as MB_per_hour ;
    select ( ( (@sequence2 - @sequence1) / 1024 / 1024 )* 60 ) * 4 as estimated_buffer_pool ;
    select ( ( ( (@sequence2 - @sequence1) / 1024 / 1024 )* 60 ) * 4 ) / 1024 as estimated_buffer_pool_GB ;



    innodb_log_file_size
    select @@innodb_log_file_size;

    I have found that I enjoy Baron's concepts on how to set the innodb_log_file_size.  Remember to execute his suggestions during peak times to get true readings. The larger the size of these files the better performance with large data sets but nothing comes for free, you will increase the recovery times. Increased recovery times might not sound like a major concern to some, until it is a revenue dependent database that you are waiting and watching process forever.  A general recommendation is to set it at  25 % of the buffer pool size.

    select ( @@innodb_buffer_pool_size * .25 )


    innodb_log_buffer_size
    select @@innodb_log_buffer_size; 

    I recall I once had this set on a server to innodb_log_buffer_size=128M.  Was it a good choice? No it means I wanted memory when I likely did not have to. It was a very write heavy database but this setting was very likely to high. Focus on the defaults first and then double it ( 8MB - 16MB ) max.


    innodb_additional_mem_pool_size
    select @@innodb_additional_mem_pool_size;

    Peter addresses this setting in his blog post. You can address it and evaluate options after other settings have been addressed in my opinion.


    innodb_flush_log_at_trx_commit
    select @@innodb_flush_log_at_trx_commit;

    > set GLOBAL innodb_flush_log_at_trx_commit =2; 
    Peter addresses this setting in his blog post as well. This is a commonly overlooked variable and worth testing performance improvement by adjusting from 0 - 2. Keep in mind the risks.


    thread_cache
    select @@thread_cache_size;
    +---------------------+
    | @@thread_cache_size |
    +---------------------+
    |                  50 |
    +---------------------+
    >show status like 'threads_created';
    +-----------------+-------+
    | Variable_name   | Value |
    +-----------------+-------+
    | Threads_created | 4     |
    +-----------------+-------+
    1 row in set (0.00 sec)

    > show status like 'connections';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | Connections   | 962   |
    +---------------+-------+
    1 row in set (0.00 sec)

    > SELECT 100 - ((4 / 962) * 100);
    +-------------------------+
    | 100 - ((4 / 962) * 100) |
    +-------------------------+
    |                 99.5842 |
    +-------------------------+

    Keep an eye on this status : show status like 'threads_created';
    If it climbs then you have it set too low and it needs to be raised.


    query_cache_size  –
    select ((@@query_cache_size / 1024) / 1024);

    The permissible values are multiples of 1024.
    Pay attention to this setting the more read dependent you application becomes.  I used to run with it set to key_buffer=16M and I could and likely should have doubled that.


    key_buffer_size
    select @@key_buffer_size;

    With MySQL switching to InnoDB as the default storage engine it is likely some we could see fewer and fewer tables created as MyISAM. That is not a fact just an opinion. The key_buffer_size will very important to you if you do utilize MyISAM tables.

    Review Shlomi Noach's post to help you find which easily which tables which engine type.
    "See per table size (almost exactly as presented in INFORMATION_SCHEMA)" -- Shlomi Noach.

    > SHOW VARIABLES LIKE 'key_buffer_size';
    +-----------------+----------+
    | Variable_name   | Value    |
    +-----------------+----------+
    | key_buffer_size | 15728640 |
    +-----------------+----------+


    table_cache
    show variables like '%table%cache%';
    +----------------------------+-------+
    | Variable_name              | Value |
    +----------------------------+-------+
    | table_definition_cache     | 4096  |
    | table_open_cache           | 4096  |
    | table_open_cache_instances | 1     |
    +----------------------------+-------+

    According to the manual this is a good formula to help determine the table_definition_cache size.
    SELECT 400 + (@@table_open_cache / 2);

    > SHOW status like '%Opened_tables%';

    table_open_cache_instances
    A value of 8 or 16 is recommended on systems that routinely use 16 or more cores, the default is 1.


    Hopefully this exposes the variables and settings that need to be reviewed to help you get the best from your MySQL database.

    No comments:

    Post a Comment

    @AnotherMySQLDBA