We have some code that goes through a SQL generator to produce parameterized IN clauses of the form WHERE id IN (?, ?, ?, ...) AND ...
.
If the list is empty, the generator cannot issue IN ()
since that is invalid SQL. Instead it issues WHERE id IN (SELECT NULL WHERE FALSE)
to provide the same semantics.
I would expect that MYSQL can reduce this to WHERE FALSE
. Interestingly though, it fails to do this and actually produces a full table scan!
Example query (mytable is a simple test table I created with 50K rows id as the PK)
select *
from mytable
where id in (select null where false);
Interestingly, if I replace the subquery with one that hits an actual table, I get a much better plan:
Query:
select *
from mytable
where id in (select null from information_schema.tables where false);
My question is, is there some reason why it makes sense for MySQL to behave this way (e.g. some particular semantic of the first query?) is this a known bug?
UPDATE: I filed this with MySQL and they've acknowledged the oddity and accepted it as a feature request.
NULL
? What value is the sub query providing?WHERE id IN NULL
is not valid SQL. The way this particular generator works lets you write something likeWHERE id IN @ids
(similar to Dapper if you're familiar with the .NET stack), so the generator gets to generate the parenthetical list but can't opt out of theIN
syntax. I'm not saying it is a perfect design; more just curious about the optimizer behavior and trying to motivate the reason behind these otherwise-odd queries :-)WHERE id IN (NULL)
like any other value rather than some convoluted sub query. Though it still doesn't give an "impossible WHERE"! In SQL Server both variants are recognized as contradictions and replaced with a constant scan dbfiddle.uk/pvrO7Jq0 - For MySQL maybe the transformation to anEXISTS
query referencingDUAL
messes with the simplification logic when no table is referenced dbfiddle.uk/10AWFfC4DUAL
still ends up less optimised than the one referencing the real table! dbfiddle.uk/Rbd9-JLtIN (SELECT 1 WHERE FALSE)
version produces the "bad" plan