However if you'd like to view your relational data gasp relationally, then the ORM is a giant anchor around your neck.
Sometimes I use sqla just for the connection pool and session handling and dump raw sql in it.
It's not raw sql vs orm, as usual it's use a spectrum with good use cases for each part of it, and you usually benefit from all of it. But orm have pareto value in my xp.
Generally, I think what people call ORMs try to do too much, and there is an impedance mismatch on many levels. Objects and relations don't map; objects are statically-defined at program compilation time, and relations are the result of a dynamic query. I think the reason that ORMs work in dynamic languages is that there isn't a rigid set of objects defined by the program; rather they can come and go during execution. So the problem becomes a problem later -- static analysis, editor tooling, etc.
Lifecycles are also complicated. You can have your ORM return dumb objects that you modify and re-store, or they can be "smart" and updated the database automatically. The "dumb object" approach neglects database transactions (multiple writers could have already modified your cached copy), and the "smart" approach neglects the networked nature of your SQL server (you may need to retry, you may need to time out if the server goes down, etc.) by pretending that some server run by another company is actually your CPU's cache.
Finally, I think it's very optimistic to write an application to support more than one database backend, which seems to be everyone's dream. Many have tried. Few have succeeded. I chalk it up as actually being O(n) work to support n databases. MySQL has some quirk that breaks Postgres's assumptions. Even the humble SQLite is different enough that is hard work to support as a secondary / test-only implementation. (I realized this, I think, when I debugged some code that worked in tests, but not in production. The tests used SQLite and did something like "insert into foo (boolean_value=1); select * from foo where boolean_value='t'". In Postgres, the inserted object is selected. In SQLite, it's not! That, to me, was the end of ever supporting two databases without the explicit requirement to do so. I'd still run my Postgres tests against Postgres and my SQLite tests against SQLite, though.)
All in all, I don't get it. Start a transaction, scan into a struct, mutate the object, write it back to the database. Not much code is required. If your mutation operation is too long to run in a transaction (i.e., it reaches out to the network for something), then you really need a state machine, which you can easily implement in your relational data model.
Ruby and Python in particular really missed the boat on this one. I feel like they cargo culted practices from Java rather than embrace the implications of their own langauge's flexibility.
I'd say the bigger hubris is trying to shove relational data into object graphs and the challenges and pain of ORMs is proof of that.
How so? I've never found this to be the case.