MySQL VIEW as Performance Troublemaker

I start to see applications being built utilizing VIEWs functionality which appeared in MySQL 5.0 and quite frequently VIEWs are used to help in writing the queries – to keep queries simple without really thinking how it affects server performance.

Even worse than that – looking at the short table which just gets single row from the table by the key we think this is a simple query, while can be a real monster instead with complexity hidden away in VIEW definition.

Just the other day I worked on optimizing application which uses VIEWs and was looking at the long-running query which just joined 2 tables… I ran EXPLAIN for it and got 200 of rows in the result set just for explaining due to several layers of cascaded views built on top of one another so it is easy to write the queries, some of them it turn used subqueries subselects and derived tables.

It is also very dangerous if you assume MySQL would optimize your VIEWs same way as more advanced database systems would. Same as with subqueries and derived tables MySQL 5.0 will fail and perform very inefficiently in many counts.

MySQL has two ways of handling the VIEWS

Query merge, in which case VIEW is simply expanded as a macro or Temporary Table in which case VIEW is materialized to temporary tables (without indexes !) which is later used further in query execution.

There does not seem to be any optimizations applied to the query used for temporary table creation from the outer query and plus if you use more then one Temporary Tables views which you join together you may have serious issues because such tables do not get any indexes.

Let me now show a couple of examples.

Assume we have the comments table which holds users comments to the blog, naturally containing user_id which left comment, comment_id and comment text:

So how would you get a number of comments left by the given user?

So how would we solve the same problem having things more modular and using MySQL VIEWs?

So we create the view which gives us back counts for each user and can simply query from that table restricting by user_id.
If this would be handled properly inside MySQL there would be even good reason to do that – so later you can change your application and convert user_count to summary table avoid changing any queries directly. Unfortunately, it does not work.

It is interesting to see EXPLAIN for such query and time for the query which fetches everything from the VIEW – it is almost the same as getting only one row, and note even EXPLAIN takes the same amount of time:

So now let’s create a very artificial query which will JOIN 2 views just to see how indexes are used: