When to use STRAIGHT_JOIN with MySQL

Viewed 59388

I just had a fairly complex query I was working with and it was taking 8 seconds to run. EXPLAIN was showing a weird table order and my indexes were not all being used even with the FORCE INDEX hint. I came across the STRAIGHT_JOIN join keyword and started replacing some of my INNER JOIN keywords with it. I noticed considerable speed improvement. Eventually I just replaced all my INNER JOIN keywords with STRAIGHT_JOIN for this query and it now runs in .01 seconds.

My question is when do you use STRAIGHT_JOIN and when do you use INNER JOIN? Is there any reason to not use STRAIGHT_JOIN if you are writing good queries?

10 Answers

I wouldn't recommend using STRAIGHT_JOIN without a good reason. My own experience is that the MySQL query optimizer chooses a poor query plan more often than I'd like, but not often enough that you should just bypass it in general, which is what you would be doing if you always used STRAIGHT_JOIN.

My recommendation is to leave all queries as regular JOINs. If you discover that one query is using a sub-optimal query plan, I would suggest first trying to rewrite or re-structure the query a bit to see if the optimizer will then pick a better query plan. Also, for innodb at least, make sure it's not just that your index statistics are out-of-date (ANALYZE TABLE). That can cause the optimizer to choose a poor query plan. Optimizer hints should generally be your last resort.

Another reason not to use query hints is that your data distribution may change over time, or your index selectivity may change, etc. as your table grows. Your query hints that are optimal now, may become sub-optimal over time. But the optimizer will be unable to adapt the query plan because of your now outdated hints. You stay more flexible if you allow the optimizer to make the decisions.

From MySQL JOIN reference:

"STRAIGHT_JOIN is similar to JOIN, except that the left table is always read before the right table. This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order."

MySQL isn’t necessarilly good at choosing the join order in complex queries. By specifying a complex query as a straight_join the query executes the joins in the order they’re specified. By placing the table to be the least common denominator first and specifying straight_join you are able to improve the query performance.

STRAIGHT_JOIN, using this clause, you can control the JOIN order: which table is scanned in the outer loop and which one is in the inner loop.

I will tell you why I had to use STRAIGHT_JOIN :

  • I had a performance issue with a query.
  • Simplifying the query, the query was suddently more efficient
  • Trying to figure out which specific part was bringing the issue, I just couldn't. (2 left joins together were slow, and each one was independently fast)
  • I then executed the EXPLAIN with both slow and fast query (addind one of the left joins)
  • Surprisingly, MySQL changed entirely the JOIN orders between the 2 queries.

Therefore I forced one of the joins to be straight_join to FORCE the previous join to be read first. This prevented MySQL to change the execution order and worked like a charm !

If your query ends with ORDER BY... LIMIT..., it may be optimal to reformulate the query to trick the optimizer into doing the LIMIT before the JOIN.

(This Answer does not apply only to the original question about STRAIGHT_JOIN, nor does it apply to all cases of STRAIGHT_JOIN.)

Starting with the example by @Accountantم, this should run faster in most situations. (And it avoids needing hints.)

SELECT  whatever
    FROM  ( SELECT id FROM sales
                ORDER BY  date, id
                LIMIT  50
          ) AS x
    JOIN  sales   ON sales.id = x.id
    JOIN  stores  ON sales.storeId = stores.id
    ORDER BY  sales.date, sales.id;

Notes:

  • First, 50 ids are fetched. This will be especially fast with INDEX(date, id).
  • Then the join back to sales lets you get only 50 "whatevers" without hauling them around in a temp table.
  • since a subquery is, by definition, unordered, the ORDER BY must be repeated in the outer query. (The Optimizer may find a way to avoid actually doing another sort.)
  • Yes, it is messier. But it is usually faster.

I am opposed to using hits because "Even if it is faster today, it may fail to be faster tomorrow."

I know it's a bit old but here's a scenario, I've been doing batch script to populate a certain table. At some point, the query ran very slow. It appears that the join order was incorrect on particular records:

  • In correct order

enter image description here

  • Incrementing the id by 1 messes up the order. Notice the 'Extra' field

enter image description here

  • Using straight_join fixes the issue

enter image description here

Incorrect order runs for about 65 secs while using straight_join runs in milliseconds

Related