A lot has happened in MySQL 5.6 for queries joining many tables.
For the most common use cases we have drastically reduced the
cost of finding the execution plan. We have also improved the
heuristics and removed bugs so that the final plan is often
better than it used to be. Read on if you are one of those people
who do 15 way joins!
Finding a query execution plan
First some background. You can skip this part if you know how
MySQL picks the table join order in 5.5.
When presented with a query, MySQL will try to find the best
order to join tables by employing a greedy search algorithm. The
outcome is what we call a query execution plan, QEP. When you
join just a few tables, there's no problem calculating the cost
of all join order combinations and then pick the best plan.
However, since there are (#tables)! possible combinations, the
cost of calculating them all soon becomes too high: for five
tables, e.g., …
Historically it was considered that MySQL will generally use only one index per referenced table in a SQL query. In MySQL 5.0 the introduction of merge indexes enabled for certain conditions the possibility to utilize two indexes however this could result in worst performance then creating a better index. In MySQL 5.1 it became possible to control optimization switches with the optimizer_switch system variable.
However in explaining how to utilize the intersection, union and sort union in queries I discovered that MySQL could use three indexes for one given table.
Extra: Using union(name,intersect(founded,type)); Using where
I was not aware of this.
Many people consider this information in the MySQL Query Execution Plan (QEP) to indicate that the referenced table is using an index. It actually means that ONLY the index is used. This can for larger and more frequent queries provide a significant boost.
In a recent example, adding an index dropped a query from 190ms to 6ms. However adding a better index dropped that 6ms query to 1.2ms. When executed 100s/1000s of times per second these millisecond improvements can have a huge benefit in greater scalability. While people often tune slow running queries, in a well tuned system shaving milliseconds of queries, in this example making 6ms query 80% better is a far greater improvement.
You can get a detailed explanation of how to identify, create and verify covering indexes from my Percona Live presentation Improving performance …
[Read more]While most people look at performance optimizations for SELECT statements, UPDATE and DELETE statements are often overlooked. These can benefit from the principles of analyzing the Query Execution Plan (QEP). You can only run an EXPLAIN on a SELECT statement, however it’s possible to rewrite an UPDATE or DELETE statement to perform like a SELECT statement.
To optimize an UPDATE, look at the WHERE clause. If you are using the PRIMARY KEY, no further analysis is necessary. If you are not, it is of benefit to rewrite your UPDATE statement as a SELECT statement and obtain a QEP as previously detailed to ensure optimal indexes are used. For example:
UPDATE t SET c1 = ‘x’, c2 = ‘y’, c3 = 100 WHERE c1 = ‘x’ AND d = CURDATE()
You can rewrite this UPDATE statement as a SELECT statement for using EXPLAIN:
EXPLAIN SELECT c1, c2, c3 FROM t WHERE c1 = ‘x’ AND d = CURDATE()
You should …
[Read more]Just recently I came across the presentation “Bend SQL to your will with EXPLAIN” by Ligaya Turmelle via the Linked In – MySQL Speakers and Presenters group. Slides available at Slideshare. While I know a little about MySQL, I always enjoy spending time reviewing content when possible, perhaps as a good reference when asked, perhaps to glean some small point of knowledge I didn’t know, or didn’t understand completely, or had forgotten about. It’s also fun to randomly find worthwhile information.
EXPLAIN is an essential tool for MySQL developers, if you don’t know what QEP is, the listed google search link …
[Read more]Before you think I’ve posted an animal story in my MySQL category please read on. For reference, The RAT and the CAT is something I wrote back in 2006, that explains the CAT part.
I was reviewing the website performance tonight of a client. I had access to an idle system so being lazy in collecting SQL after my initial audit of the system and MySQL, I turned on the General Query log and hit the home page. NOTE: Do not do this on a running production system, especially with any volume.
What I got was 77 lines of output (after I removed newlines in the queries). 74 were queries, and 72 were from the same table, via some unnecessarily complex sub-joins. I wish I could have laughed but it wasn’t really funny.
My Friday wisdom for writing SQL is this:
- Don’t write duplicate SQL statements
- Look the entire …
It is important to know and understand that while indexing columns in MySQL will generally improve performance, using the appropriate type of index can make a greater impact on performance.
There are four general index types to consider when creating an appropriate index to optimize SQL queries.
- Column Index
- Concatenated Index
- Covering Index
- Partial Index
For the purpose of this discussion I am excluding other specialized index types such as fulltext, spatial and hash in memory engine.
Example Table
For the following examples, I will use this test table structure.
DROP TABLE IF EXISTS t1; CREATE TABLE t1( id INT UNSIGNED NOT NULL AUTO_INCREMENT, user_name VARCHAR(20) NOT NULL, first_name VARCHAR(30) NOT NULL, last_name VARCHAR(30) NOT NULL, external_id INT UNSIGNED NOT NULL, country_id SMALLINT UNSIGNED NOT NULL, PRIMARY KEY(id) ) …[Read more]
I was surprised to find yesterday when using MySQL 5.1.26-rc with a client I’m recommending 5.1 to, some information not seen in the EXPLAIN plan before while reviewing SQL Statements.
Using join buffer
+----+-------------+-------+--------+---------------+--------------+---------+------------------------+-------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+--------------+---------+------------------------+-------+----------------------------------------------+ | 1 | SIMPLE | lr | ALL | NULL | NULL | NULL | NULL | 1084 | Using where; Using temporary; Using filesort | | 1 | SIMPLE | ca | ref | update_check | update_check | 4 | XXXXXXXXXXXXXXXXX | 4 | Using …[Read more]