NULL values are suprisingly hazardous for MySQL's way of optimizing IN subqueries. MySQL takes the '=' from '=ANY' and tries to push it down into the subquery, essentially changing IN subquery into EXISTS subquery. That is, a subquery like
outer_expr IN (SELECT inner_expr FROM ... WHERE subq_where)
is converted to:
EXISTS (SELECT 1 FROM ... WHERE subq_where AND outer_expr=inner_expr)
and then MySQL can use the pushed-down equality to limit number of rows it has to look through when running the subquery. This "pushdown" works as long as outer_expr and inner_expr can't be NULL or you don't care whether subquery result is NULL or FALSE (MySQL figures that you don't care if the subquery is a part of OR or AND expression in the WHERE clause).When you start caring about producing correct NULL or FALSE results, problems start coming from left and right, literally:
NULL problem in the right part
…
[Read more]