Have you tried MySQLTuner yet? It's free and it makes optimizing your MySQL server easier than ever!

Archive for the “Database” Category


I finally remembered this book when someone asked me about how to get started with PHP and MySQL development. If you get the chance, get a copy of this book:

PHP and MySQL Web Development by Luke Welling, Laura Thomson
Barnes & Noble: http://snurl.com/265xp

Why do I like this book so much?

  • Teaching by application - The book teaches fundamentals by showing how to apply techniques to an active website. There’s not a ton of theory to wade through, and you feel like you’re learning the material faster.
  • Intertwined strategies - You learn how to get PHP working with MySQL, and then you learn how to optimize your code. It’s important to know which work is best done by PHP and which is best done by MySQL. This book teaches both.
  • Lots of examples - The CD-ROM comes with tons of code examples that actually relate to something you can use.

I’d be happy to loan my copy, but I’ve loaned it out and it never returned.

Comments 1 Comment »

Before getting started, it’s important to understand why MySQL uses locks. In short - MySQL uses locks to prevent multiple clients from corrupting data due to simultaneous writes while also protecting clients from reading partially-written data.

Some of you may be thinking, “Okay, this makes sense.” If that’s you, skip the next two paragraphs. If not, keep reading.

Analogies can help understand topics like these. Here’s one that I came up with during a training class. Consider two people sitting in front of a notepad on a table. Let’s say that a sentence like “The quick brown fox jumps over the lazy dog” is already written on the notepad. If both people want to read the sentence simultaneously, they can do so without getting in each other’s way. A third or fourth person could show up and they could all read it at the same time.

Well, let’s say one of the people at the table is writing a screenplay for Cujo, and they want to change “lazy” to “crazy”. That person erases the “l” in “lazy” and then adds a “cr” to the front to spell “crazy”. So if the other person is reading the sentence while the first person is writing, they will see “lazy” turn into “azy”, then “c_azy”, and then finally, “crazy”. This isn’t a big issue in real life, but on the database level, this could be dangerous. If the person who was reading the sentence showed up during the middle of the letter changes, they would think that the dog was “azy”, and they’d walk away wondering what the adjective “azy” means. To get around this, MySQL uses locking to block clients from reading data while it’s being written and it blocks clients from writing data simultaneously.

Now that we’re all familiar with what locks are, and why MySQL uses them, let’s talk about some ways to reduce the delays caused by locking. Here’s some situations you might be running up against:

Writes are delayed because reads have locked the tables
This is the most common occurrence from the servers that I have seen. When you run a SHOW PROCESSLIST, you may see a few reads at the top of the queue that are in the status of “Copying to tmp table” and/or “Sending data”. On optimized servers running optimized queries, these should clear out quickly. If you’re finding that they are not clearing out quickly, try the following:

  • Use EXPLAIN on your queries to be sure that they are optimized
  • Add indexes to tables that you query often
  • Reduce the amount of rows that are being returned per query
  • Upgrade the networking equipment between web and database servers (if applicable)
  • Consider faster hardware with larger amounts of RAM
  • Use MySQLTuner to check your current server’s configuration for issues
  • Consider moving to InnoDB to utilize row-based locking

Reads and writes are delayed because writes have locked the tables
Situations like these are a little different. There’s two main factors to consider here: either MySQL cannot write data to the disk fast enough, or your write queries (or tables) are not optimized. If you suspect a hardware issue, check your iowait with sar and see if it stays at about 10-20% or higher during the day. If it does, slow hardware may be the culprit. Try moving to SCSI disks and be sure to use RAID 5 or 10 for additional reliability and speed. SAN or DAS units may also help due to higher throughput and more disk spindles.

If you already have state-of-the-art hardware, be sure that your tables and queries are optimized. Run OPTIMIZE TABLES regularly if your data changes often to defragment the tables and clear out any holes from removed or updated data. Slow UPDATE queries suggest that you are updating too many rows, or you may be using a column in the WHERE clause that is not indexed. If you do a large amount of INSERT queries, use this syntax to enter multiple rows simultaneously:

INSERT INTO table (col1,col2) VALUES ('a','1'), ('b','2'), ('c','3');

This syntax tells MySQL to hold off on updating indexes until the entire query is complete. If you are updating a very large amount of rows, and you need to use multiple queries to avoid reaching the max_allowed_packet directive, you can do something like this:

ALTER TABLE table DISABLE KEYS;
INSERT INTO table (col1,col2) VALUES ('a','1'), ('b','2'), ('c','3');
~~~ many more inserts ~~~
ALTER TABLE table ENABLE KEYS;

This forces MySQL to not calculate any new index information until you re-enable the keys or run OPTIMIZE TABLE. If all of this does not help, consider using InnoDB as your storage engine. You can benefit from the row-level locking, which reduces locking in mixed read/write scenarios. In addition, InnoDB is able to write data much more efficiently than MyISAM.

Comments 2 Comments »

MySQLTuner v0.9.0 is now available. There is a bug fix and also a new feature!

Fixed a bug in the enumeration/sizing of tables in MySQL 5
In MySQL 5 on some distributions, a NULL is returned for the storage engine and data length. Luuk Vosslamber quickly e-mailed me about the bug yesterday and it has been fixed.

MySQLTuner version checking
MySQLTuner will now check to see if a new version is available when the script runs. You can disable the check with the --skipversion option if you do not wish to perform the check.

The version check does not submit any information about the server, the MySQL installation, or any of your MySQL data. It simply queries a page on mysqltuner.com with the version number of your currently running script. Based on the value returned by the page, MySQLTuner will alert you if a new version is available.

To download the new version right now, please go to the project page and use the download links.

Comments 2 Comments »

MySQLTuner v0.8.9 is now available.  There are a few bug fixes, performance improvements, and readability adjustments.

Table enumeration and sizing can now be skipped
I’ve received reports that MySQLTuner will stall while enumerating tables on servers that contain a lot of tables or a lot of large tables.  You can now use the --skipsize option to skip over the table enumeration process and let the script finish.  However, you will not be able to receive some recommendations since the script was unable to determine which storage engines are enabled.

New table enumeration and sizing method for MySQL 5
The script now uses information_schema to enumerate tables and their sizes for MySQL 5 servers.  This has provided a drastic improvement in performance.

Readability improvements
The recommendations for query_cache_limit and max_heap_table_size/tmp_table_size have been improved.

As always, I welcome your suggestions, bug reports, and questions!  Please feel free to drop a comment on this blog posting or send me an e-mail (it’s in the script).  Also, don’t forget to sign up for the MySQLTuner version announcement list.

Comments No Comments »

It’s tough to find examples of dumps that can’t be properly reimported on other servers. However, if you have a 64-bit server, and you make a MySQL dump file from it, you may see this issue when importing the dump on a 32-bit MySQL server:

ERROR 1118 (42000) at line 1686: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs

You really don’t have any options in this situation. You’ll need to adjust your table on the 64-bit server for good and then make a new dump file, or you will just have to live with the fact that it can’t be imported into a 32-bit instance of MySQL.

Comments No Comments »

Version 0.8.6 of MySQLTuner is now available. It contains a few bug fixes and readability improvements:

Newlines are placed between the sections for increased readability
Each section now contains extra lines to set the sections apart. It makes the output a little longer, but easier to read as well.

Storage engine status color bug
Even if the –nocolor option was passed, the storage engine statuses were being shown in color.

Excluded information_schema from storage engine calculations
The information_schema database was causing extra MEMORY tables to show up in the calculations. They’re now excluded when the calculations are being made.

Shawn Ashlee has also been added as a contributor as he’s been a constant help for the project. He’s recommended implementation ideas and he has worked to create internal MySQLTuner RPM’s for use at Rackspace. Thanks, Shawn!

Comments 4 Comments »

Due to popular demand, I’ve created a mailing list for MySQLTuner. It will be a low-traffic list consisting of new version announcements and bug fixes.

If you want to subscribe, simply send an e-mail with SUBSCRIBE in the subject line to mysqltuner-announce-request@mysqltuner.com. Be sure to add mysqltuner-announce@mysqltuner.com to your mail provider’s whitelist.

Comments No Comments »

To get the latest copy, head over to the download page! Here’s the changes from 0.8.0 to 0.8.5 for MySQLTuner:

Fixed a copy/paste bug
There was a bug in 0.8.0 that displayed “OK” in red rather than showing “!!”. It affected the informational “–” outputs as well. Thanks to Nils Breunese for pointing out that confusing bug!

Fixed a data length calculation bug with MySQL 4.0
If the script was run against MySQL 4.0 servers, it would return the Max_data_length rather than Data_length, and this was returning some horribly incorrect results for the size of tables in use with certain storage engines.

Fixed a key buffer calculation bug with MySQL 4.0
It’s not possible to ask a MySQL 4.0 server about how much of the key buffer is in use, so the functionality for MySQL 4.0 now matches 3.23 for key buffer calculations.

Added a notification for well-optimized servers
For situations where MySQLTuner can’t make any recommendations for performance increases, it actually says so now.

Version bump to 0.8.5
It’s getting close to a full 1.0 release!

Comments No Comments »

Thanks to an e-mail from Joe Calderon, I’ve corrected a MySQLTuner bug where indexes were not being calculated properly when symbolic links are used. It was a quick fix, and the new version is now available for download.

Also, MySQLTuner now has a standardized versioning scheme. I’m starting at 0.8.0 since I’m close to a completely stable release. There’s still a few kinks when working with MySQL cluster nodes, and I’m hoping to work that out soon.

Thanks for downloading!

Comments No Comments »

One of the questions I receive the most is: “What version of Plesk works with MySQL 5?” The minimum version of Plesk for MySQL 5 is 8.1.0. If you install MySQL 5 on a version prior to 8.1.0, you may be able to access then panel in the other 8.x versions, but your upgrades will fail miserably.

In case you’re curious about a slightly older system, full MySQL 4 support was available in Plesk 7.5.3. However, MySQL 4 is supported on some distributions as far back as 7.1:

Fedora Core 2
Mandrake 10
SuSE 9.0
FreeBSD 5.2.1

Check out SWSoft/Parallel’s site for more information about MySQL 4 and 5 support.

Comments No Comments »