In my experience, everything else about optimizing a LAMP server is pretty easy. But MySql is a bitch. Most of the times I run into slow running database driven sites, I have to go no further than MySql. And if your MySql installation is not optimized, I can tell you without a doubt that until it is, speeding up any other part of your site isn’t going to make much of a dent.
I do have one site running only on Webmin and Webmin does nothing to MySql settings and MySql out of the box is not optimized. It should be tweaked to the needs of your site. But that really is the topic for a whole ‘nother blog, really. MySql can be a very complex mess.
But there is a tool called MySql Tuner that will help you optimize your MySql installation. At least it will give you places to look.
To use it, simply Putty into your server and type the following two lines:
wget mysqltuner.pl
perl mysqltuner.pl
After that is done, your Putty window should spit out text similar to this:
wget mysqltuner.pl
--2010-11-27 07:18:22-- http://mysqltuner.pl/
Resolving mysqltuner.pl... 174.143.142.58
Connecting to mysqltuner.pl|174.143.142.58|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://mysqltuner.pl/mysqltuner.pl [following]
--2010-11-27 07:18:23-- http://mysqltuner.pl/mysqltuner.pl
Reusing existing connection to mysqltuner.pl:80.
HTTP request sent, awaiting response... 200 OK
Length: 39054 (38K) [text/plain]
Saving to: `mysqltuner.pl'
100%[======================================>] 39,054 --.-K/s in 0.1s
2010-11-27 07:18:23 (271 KB/s) - `mysqltuner.pl' saved [39054/39054]
[root@hostserver tmp]# perl mysqltuner.pl
>> MySQLTuner 1.0.1 - Major Hayden
>> Bug reports, feature requests, and downloads at http://mysqltuner.com/
>> Run with '--help' for additional options and output filtering
Please enter your MySQL administrative login:
Please enter your MySQL administrative password:
-------- General Statistics --------------------------------------------------
[--] Skipped version check for MySQLTuner script
[OK] Currently running supported MySQL version 5.0.77
[OK] Operating on 32-bit architecture with less than 2GB RAM
-------- Storage Engine Statistics -------------------------------------------
[--] Status: -Archive +BDB -Federated +InnoDB -ISAM -NDBCluster
[--] Data in MyISAM tables: 295M (Tables: 321)
[--] Data in InnoDB tables: 1M (Tables: 7)
[!!] BDB is enabled but isn't being used
[!!] Total fragmented tables: 38
-------- Performance Metrics -------------------------------------------------
[--] Up for: 1h 10m 40s (41K q [9.728 qps], 782 conn, TX: 117M, RX: 9M)
[--] Reads / Writes: 63% / 37%
[--] Total buffers: 40.0M global + 2.7M per thread (300 max threads)
[!!] Maximum possible memory usage: 846.2M (165% of installed RAM)
[OK] Slow queries: 0% (72/41K)
[OK] Highest usage of available connections: 5% (15/300)
[OK] Key buffer size / total MyISAM indexes: 2.0M/50.3M
[OK] Key buffer hit rate: 99.4% (716K cached / 4K reads)
[OK] Query cache efficiency: 25.9% (6K cached / 26K selects)
[!!] Query cache prunes per day: 26898
[OK] Sorts requiring temporary tables: 0% (0 temp sorts / 543 sorts)
[!!] Joins performed without indexes: 328
[!!] Temporary tables created on disk: 32% (326 on disk / 994 total)
[OK] Thread cache hit rate: 98% (15 created / 782 connections)
[OK] Table cache hit rate: 96% (149 open / 155 opened)
[OK] Open file limit used: 11% (272/2K)
[OK] Table locks acquired immediately: 97% (31K immediate / 31K locks)
[OK] InnoDB data size / buffer pool: 1.6M/8.0M
-------- Recommendations -----------------------------------------------------
General recommendations:
Add skip-bdb to MySQL configuration to disable BDB
Run OPTIMIZE TABLE to defragment tables for better performance
MySQL started within last 24 hours - recommendations may be inaccurate
Reduce your overall MySQL memory footprint for system stability
Enable the slow query log to troubleshoot bad queries
Adjust your join queries to always utilize indexes
When making adjustments, make tmp_table_size/max_heap_table_size equal
Reduce your SELECT DISTINCT queries without LIMIT clauses
Variables to adjust:
*** MySQL's maximum memory usage is dangerously high ***
*** Add RAM before increasing MySQL buffer variables ***
query_cache_size (> 12M)
join_buffer_size (> 128.0K, or always use indexes with joins)
tmp_table_size (> 32M)
max_heap_table_size (> 16M)
First you get the stats and the metrics:
[OK] is obviously good.
[!!] is an issue and
[--] is just information
And after that comes the suggested fixes. The lines that scared me was “*** MySQL’s maximum memory usage is dangerously high ***Â *** Add RAM before increasing MySQL buffer variables ***”. Not much I could do about that expect moving to another server. So I was going to try to see what I could do with the rest. It was taking 90% of the processor at the time.
Running OPTIMIZE TABLE always helps a bit but it is not a really big issue causer.
And really, this did tell me a lot to find a few issues. Of course, if you have anything other than a very basic PHP/MySql site, suggestions like “Adjust your join queries to always utilize indexes” will take a while to optimize. Well, not if you spend just a little time watching your MySql connections. Usually connections are there and gone quickly, but if you see a few hanging around for a while, you should get a listing of what query is being run at that connection. In mine, I saw JOINS in the queries so I went to make sure the joined columns were indexes. One was not. I also happened to see me using LIKE when = would do and NOT LIKE when <> would do.
I quickly found the files the queries were being run from and fixed the issues. Now I can’t catch a connection hanging around long enough to give me another query to optimize. Both of these were queries i never should have written, but since I am self taught, it took me a while to learn MySql query optimization. It is not the type of thing you learn in beginners books.
The rest of the steps involve editing the MySql Configuration file like so:
skip-bdb
query_cache_size=12M
tmp_table_size=32M
max_heap_table_size=32M
join_buffer_size=128K
And I will have to say that sped up things quite a bit with no more queries hanging around forever. I had done some MySql tuning manually with decent success but I will have to say having the MySqlTuner script around helped a whole lot.