Increasing slow MySQL query performance with the parallel query execution

January 7, 2014
Author
Alexander Rubin
Share this Post:

MySQL and Scaling-up (using more powerful hardware) was always a hot topic. Originally MySQL did not scale well with multiple CPUs; there were times when InnoDB performed poorer with more CPU cores than with fewer CPU cores. MySQL 5.6 can scale significantly better; however, there is still 1 big limitation: 1 SQL query will eventually use only 1 CPU core (no parallelism). Here is what I mean by that: let’s say we have a complex query which will need to scan millions of rows and may need to create a temporary table; in this case MySQL will not be able to scan the table in multiple threads (even with partitioning) so the single query will not be faster on the more powerful server. On the contrary, a server with more slower CPUs will show worse performance than the server with less (but faster) CPUs.

MySQL parallel query execution

To address this issue we can use a parallel query execution. Vadim wrote about the PHP asynchronous calls for MySQL. Another way to increase the parallelism will be to use “sharding” approach, for example with Shard Query. I’ve decided to test out the parallel (asynchronous) query execution with a relatively large table: I’ve used the US Flights Ontime performance database, which was originally used by Vadim in the old post Analyzing air traffic performance. Let’s see how this can help us increase the performance of the complex query reports.

Parallel Query Example

To illustrate the parallel query execution with MySQL I’ve created the following table:

And loaded 26 years of data into it. The table is 56G with ~152M rows.

Software: Percona 5.6.15-63.0. Hardware: Supermicro; X8DTG-D; 48G of RAM; 24xIntel(R) Xeon(R) CPU L5639 @ 2.13GHz, 1xSSD drive (250G)

So we have 24 relatively slow CPUs

Simple query

Now we can run some queries. The first query is very simple: find all flights per year (in the US):

As we have the index on YearD, the query will use the index:

The query is simple, however, it will have to scan 150M rows. Here is the results of the query (cached):

The query took 54 seconds and utilized only 1 CPU core. However, this query is perfect for running in parallel.  We can run 26 parallel queries, each will count its own year. I’ve used the following shell script to run the queries in the background:

Here are the results:

So the total execution time is ~5 (10x faster) seconds. Each individual results are here:

Complex Query 

Now we can try a more complex query. Let’s imagine we want to find out which airlines have maximum delays for the flights inside the continental US during the business days from 1988 to 2009 (I was trying to come up with the complex query with multiple conditions in the where clause).

As the query has “group by” and “order by” plus multiple ranges in the where clause it will have to create a temporary table:

(for this query I’ve created the combined index: KEY comb1 (Carrier,YearD,ArrDelayMinutes)  to increase performance)

The query runs in ~15 minutes:

 

Now we can split this query and run the 31 queries (=31 distinct airlines in this table) in parallel. I have used the following script:

In this case, we will also avoid creating a temporary table  (as we have an index which starts with carrier).

Results: total time is 5 min 47 seconds (3x faster)

Per query statistics:

As we can see there are large airlines (like AA, UA, US, DL, etc) which took most of the time. In this case, the load will not be distributed evenly as in the previous example; however, by running the query in parallel we have got 3x times better response time on this server.

CPU utilization:

Note that in case of “order by” we will need to manually sort the results, however, sorting 10-100 rows will be fast.

Conclusion

Splitting a complex report into multiple queries and running it in parallel (asynchronously) can increase performance (3x to 10x in the above example) and will better utilize modern hardware. It is also possible to split the queries between multiple MySQL servers (i.e. MySQL slave servers) to further increase scalability (will require more coding).

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Far
Enough.

Said no pioneer ever.
MySQL, PostgreSQL, InnoDB, MariaDB, MongoDB and Kubernetes are trademarks for their respective owners.
© 2026 Percona All Rights Reserved