Monday, March 29, 2010

MySQL is so slow on Windows... Really?

Last week a customer called me and reported that MySQL was 30 times slower than MS SQL server. Oooops. That's a lot. No way to argue or throw smoke bombs. 30 times slower!
It was a standard installation of MySQL (typical install option) on plain Windows 7 and the same for MS SQL Server 2008. The test run was a batch of 30.000 INSERT commands in an SQL script. Runtime was 1 minute on MSSQL and 30 minutes on MySQL.
Some tests later we found out that it was only bad on InnoDB. MyISAM was as fast as MSSQL. (I didn't care which one was a bit faster. I didn't care as long as InnoDB was 30 times slower) Finally we nailed the problem down to one parameter in MySQL:
Each INSERT statement is a single transaction (autocommit mode). MySQL is configured very faithfully and ensures that each transaction is really stored on disk. This is necessary for ACID compliance. D in ACID stands for 'durability'. To store data durable, at least the log file has to be written physically. That's why MySQL when a transaction commits forces the operating system to flush its buffers and even forces the disk cache to flush its buffer. That's the meaning of flush_log_at_trx_commit = 1 in the my.ini or my.cnf file.
MSSQL is much more relaxed with your data. It writes the data to disk device. But it may stay in the disk cache, and MSSQL does not care. If you have a crash, your data is not up-to-date on the physical disk and you may lose data. This is definitely not ACID compliant. Microsoft documented this here:
  • By default, the disk cache is enabled. Use the 'Disk Properties', Hardware tab to access the 'Properties', 'Policy' tab to control the disk cache setting. (Note Some drives do not honor this setting. These drives require a specific manufacturer utility to disable cache.)
  • ...
  • Disk caching should be disabled in order to use the drive with SQL Server.
So to have a fair comparison beween MSSQL and MySQL either
  • set innodb_flush_log_at_trx_commit = 0 (or 2)
    This forces the flush to disk only once per second and brings good performance but data is not 100% safe on disk (unless you have a battery backed write cache)
  • disable the disk cache in Windows 7
    This will force MSSQL to write physically to disk. And then MSSQL is 30 times slower than before. ;-)
Lessons learned:
  • Think a lot about how to do a fair comparison.
  • Either run (unsafe and fast), or (safe and slow) or (safe and fast and expensive) with a battery backed write cache controller
  • Read the manual for MSSQL. There may be important news on page 3647+x.
The funny thing, that confused me a lot: On my Mac InnoDB was at around 1 minute. And even MySQL on Windows 7 in Virtual Box on my Mac was about 1 minute. The reason is: MySQL on Mac makes a fsync() that does not flush the disk cache. It flushes only the buffer cache of the operating system. And Windows 7 on Virtual Box: The disk is a plain file on the host OS. And this file is of course buffered in the host OS. So Virtualization may destroy your ACID compliance...
If you need more info on the different cache levels for file IO here is a very good link:


  1. Best performance will be with set innodb_flush_log_at_trx_commit = 0
    As stated in MySQL config:

    If set to 1, InnoDB will flush (fsync) the transaction logs to the
    disk at each commit, which offers full ACID behavior. If you are
    willing to compromise this safety, and you are running small
    transactions, you may set this to 0 or 2 to reduce disk I/O to the
    logs. Value 0 means that the log is only written to the log file and
    the log file flushed to disk approximately once per second. Value 2
    means the log is written to the log file at each commit, but the log
    file is only flushed to disk approximately once per second.

    1. You are right. I will add that to the blog post. Thanks for spotting this.

  2. Thank you for sharing. Your blog has given me that thing which I never expect to get from all over the websites. Nice post guys!

    Melbourne Web Developer