Materialized Views in MySQL
Update: Dynamic Materialized Views
Please read this article also. Its an improved versio of the technique described below.
Today i found a workaround for a feature that was realy missing in MySQL.
Let’s say you got a really complicated query that requires a lot of cpu and time to complete, but the resulting data is quite static. That’s the perfect opportunity to use a “Materialized View”. The Bad Thing™ is, mysql does not support what’s usually known as materialized views. But today i found a nice workaround for MySQL 5.
But first let’s clarify what a materialized view is. I found a good explanation here:
“A materialized view is a stored summary containing precomputes results (originating from an SQL select statement).
As the data is precomputed, materialized views allow for (seemingly) faster dataware query answers.”
Okay, so a materialized view saves the result of a query somewhere (e.g. into another table) else.
In my case i had to calculate a rating of users based on votes from other users (Website of http://www.hiphop-battles.com btw) . I’m doing this with some nested views (also a new feature in MySQL5). The whole calculation and query took 0.5 seconds on my athlon xp 3200 machine. Thats way to much to run this query on each page impression.
The trick is a new feature that was introduced in MySQL 5. From the MySQL Manual:
“In MySQL 5.0, you can create one table from another by adding a SELECT statement at the end of the CREATE TABLE statement:
CREATE TABLE new_tbl SELECT * FROM orig_tbl;“
So its possible to create a new table with structure based on an already existing table. The data of the table gets copied also.
To create a table of a very processing intensive view we run the following query:
CREATE TABLE view_m_demo SELECT * FROM view_demo;
To make it little bit better we put this code into a procedure (also a new feature in MySQL5):
DELIMITER //
CREATE PROCEDURE updateDemoView ()
BEGIN
DROP TABLE IF EXISTS view_m_demo;
CREATE TABLE view_m_demo SELECT * FROM view_demo;
END; //
DELIMITER ;
Now we can call this procedure using a trigger:
delimiter //
CREATE TRIGGER T_updateDemoView AFTER INSERT ON some_involved_table
FOR EACH ROW BEGIN
/* calls the procedure to update out materialized view on each insert */
CALL updateDemoView ();
END //
delimiter ;
The same can be done with an “AFTER UPDATE” trigger. dont use database triggers if the data in the original tables get updated frequently.
Another option in this case is to update the view time triggerd via cron.
To update the materialized view every minute use:
*/1 * * * * echo "CALL updateDemoView ();" | mysql -u user --password=pass database
I hope this helps somebody as much as it helps my projects website loading time ;)
before: 0,48 sec
after: 0,003 sec
























Roland Bouman said
am October 27 2005 @ 11:07 am
Hi !
nice one, glad you solved your problem.
Have you thought of writing triggers for all events that would result in an modification of the data in the MVIEW, and have those changes being incrementally pushed through immediately when the event occurs? I suspect that would be a more balanced solution especially when you have some DML going on.
Nice thing about your solution is that it’s so simple. Drawback is of course that you only have the FOR EACH ROW triggers, you’d rather use AFTER STATEMENT for this one.
BTW, you can have MySQL perform periodical procedure calls without cron or external tools, check it out:
http://rpbouman.blogspot.com/2005/10/scheduling-procedure-execution-in.html
This relies on the MySQL SLEEP() function.
Marcel Oelke said
am October 27 2005 @ 11:37 am
Thanks for your intresting comment Roland. I am not using the trigger in my case because the data in the tables the view builds uppon is changed very frequently. Besides i haven’t found the “AFTER STATEMENT” for triggers in the mysql documentation.
Your scheduling procedures are very intresting. maybe i’ll will use them instead of cron. thanks for that hint !
puRe
Roland Bouman said
am October 28 2005 @ 2:09 pm
Sorry, I should’ve been more clear on that. When I said: ‘Drawback is of course that you only have the FOR EACH ROW triggers..’ I did not mean that that was a problem in your code; i just meant the general sense of ‘you’; so that it would read: ‘Drawback is of course that FOR EACH STATEMENT triggers are not supported’. My fault, sorray again.
As for frequently changing data: that’s were I think you could build an excellent solution by having each indidual change being pushed through incrementally, without reevalutating the entire set. If you post an example of your tables and your view, I’ll show you how.
Roland.
David said
am March 20 2006 @ 3:09 pm
When the select query is quite heavy isn’t it more profitable to update the view instead of re-creating it?
Matt said
am August 28 2006 @ 9:58 am
Sounds like a cron job to me! :)
Cheers for the info.
ezani said
am February 3 2009 @ 8:58 am
Sorry I may have misunderstood this completely but I do not see the point of duplicating a table which already exists. Why not just use (and update or refresh) the original table ? :-o