If you're doing complex reporting queries, an ORM is strictly worse. And yes, I've seen developers, architects, and authors of ORMs that believed otherwise. They are wrong.
As an example, very, very few ORMs can make the distinction between
SELECT ...
FROM foo
LEFT JOIN bar
ON foo.id = bar.foo_id
AND bar.category_id = 5
LEFT JOIN baz
ON bar.id = baz.bar_id
...
and SELECT ...
FROM foo
LEFT JOIN bar
ON foo.id = bar.foo_id
LEFT JOIN baz
ON bar.id = baz.bar_id
AND bar.category_id = 5
...
(And if you get into things like analytic queries, just forget about it.)If so, the result of the query would be identical but the second one would likely have performance problems given the category_id filter is not being applied at the point where bar is joined. A clever database engine might find an optimisation but I wouldn't count on it.
This illustrates the subtle problem that ORMs can introduce - all logical tests pass but issues emerge over time. I found that typically every ORM based problem was resolved by rewriting it using SQL.
I used to use ORMs extensively, but my philosophy now is that you can make simple queries by using a query generator (i.e. connection.GetByID("MyTable", 100)) and complex queries have to be written by hand. I would not choose to use an ORM again.
With inner joins the semantics are the same. If the performance is different, the database query optimizer is broken.
However, I'm reasonably certain we'd see poor performance with that query on MySQL 5.7, but I don't think it's got as good an optimiser as Postgres for example.
Even SQLite figures this one out and does it right.
In the second case, the first join will always return a row from bar for a given foo_id if it exists, but the second join does not return values from baz for rows where bar.category_id <> 5.