物化視圖,它是用於預先計算並保存表連接或聚集等耗時較多的操作的結果,這樣,在執行查詢時,就可以避免進行這些耗時的操作,從而快速的得到結果。物化視圖有很多方面和索引很相似:使用物化視圖的目的是為了提高查詢性能;物化視圖對應用透明,增加和刪除物化視圖不會影響應用程序中SQL 語句的正確性和有效性;物化視圖需要占用存儲空間;當基表發生變化時,物化視圖也應當刷新
創建自己的物化視圖
DROP TABLE sales_mv; CREATE TABLE sales_mv ( product_name VARCHAR(128) NOT NULL , price_sum DECIMAL(10,2) NOT NULL , amount_sum INT NOT NULL , price_avg FLOAT NOT NULL , amount_avg FLOAT NOT NULL , sales_cnt INT NOT NULL , UNIQUE INDEX product (product_name) ); INSERT INTO sales_mv SELECT product_name , SUM(product_price), SUM(product_amount) , AVG(product_price), AVG(product_amount) , COUNT(*) FROM sales GROUP BY product_name;
當有需要時對物化視圖進行刷新,存儲過程如下
DROP PROCEDURE refresh_mv_now; DELIMITER $$ CREATE PROCEDURE refresh_mv_now ( OUT rc INT ) BEGIN TRUNCATE TABLE sales_mv; INSERT INTO sales_mv SELECT product_name , SUM(product_price), SUM(product_amount) , AVG(product_price), AVG(product_amount) , COUNT(*) FROM sales GROUP BY product_name; SET rc = 0; END; $$ DELIMITER ;
立刻刷新物化視圖,當執行insert,delete和update時
創建相關觸發器
DELIMITER $$ CREATE TRIGGER sales_ins AFTER INSERT ON sales FOR EACH ROW BEGIN SET @old_price_sum = 0; SET @old_amount_sum = 0; SET @old_price_avg = 0; SET @old_amount_avg = 0; SET @old_sales_cnt = 0; SELECT IFNULL(price_sum, 0), IFNULL(amount_sum, 0), IFNULL(price_avg, 0) , IFNULL(amount_avg, 0), IFNULL(sales_cnt, 0) FROM sales_mv WHERE product_name = NEW.product_name INTO @old_price_sum, @old_amount_sum, @old_price_avg , @old_amount_avg, @old_sales_cnt ; SET @new_price_sum = @old_price_sum + NEW.product_price; SET @new_amount_sum = @old_amount_sum + NEW.product_amount; SET @new_sales_cnt = @old_sales_cnt + 1; SET @new_price_avg = @new_price_sum / @new_sales_cnt; SET @new_amount_avg = @new_amount_sum / @new_sales_cnt; REPLACE INTO sales_mv VALUES(NEW.product_name, @new_price_sum, @new_amount_sum, @new_price_avg , @new_amount_avg, @new_sales_cnt) ; END; $$ DELIMITER ;
DELIMITER $$ CREATE TRIGGER sales_del AFTER DELETE ON sales FOR EACH ROW BEGIN SET @old_price_sum = 0; SET @old_amount_sum = 0; SET @old_price_avg = 0; SET @old_amount_avg = 0; SET @old_sales_cnt = 0; SELECT IFNULL(price_sum, 0), IFNULL(amount_sum, 0), IFNULL(price_avg, 0) , IFNULL(amount_avg, 0), IFNULL(sales_cnt, 0) FROM sales_mv WHERE product_name = OLD.product_name INTO @old_price_sum, @old_amount_sum, @old_price_avg , @old_amount_avg, @old_sales_cnt ; SET @new_price_sum = @old_price_sum - OLD.product_price; SET @new_amount_sum = @old_amount_sum - OLD.product_amount; SET @new_price_avg = @new_price_sum / @new_amount_sum; SET @new_sales_cnt = @old_sales_cnt - 1; SET @new_amount_avg = @new_amount_sum / @new_sales_cnt; REPLACE INTO sales_mv VALUES(OLD.product_name, @new_price_sum, @new_amount_sum , IFNULL(@new_price_avg, 0), IFNULL(@new_amount_avg, 0) , @new_sales_cnt) ; END; $$ DELIMITER ;
DELIMITER $$ CREATE TRIGGER sales_upd AFTER UPDATE ON sales FOR EACH ROW BEGIN SET @old_price_sum = 0; SET @old_amount_sum = 0; SET @old_price_avg = 0; SET @old_amount_avg = 0; SET @old_sales_cnt = 0; SELECT IFNULL(price_sum, 0), IFNULL(amount_sum, 0), IFNULL(price_avg, 0) , IFNULL(amount_avg, 0), IFNULL(sales_cnt, 0) FROM sales_mv WHERE product_name = OLD.product_name INTO @old_price_sum, @old_amount_sum, @old_price_avg , @old_amount_avg, @old_sales_cnt ; SET @new_price_sum = @old_price_sum + (NEW.product_price - OLD.product_price); SET @new_amount_sum = @old_amount_sum + (NEW.product_amount - OLD.product_amount); SET @new_sales_cnt = @old_sales_cnt; SET @new_price_avg = @new_price_sum / @new_sales_count; SET @new_amount_avg = @new_amount_sum / @new_sales_cnt; REPLACE INTO sales_mv VALUES(OLD.product_name, @new_price_sum, @new_amount_sum , IFNULL(@new_price_avg, 0), IFNULL(@new_amount_avg, 0) , @new_sales_cnt) ; END; $$ DELIMITER ;
參考:http://www.fromdual.com/mysql-materialized-views#implement
