您的位置:首页 > 数据库 > MySQL

使用mysql创建自己的物化视图

2013-06-25 14:11 260 查看
  物化视图,它是用于预先计算并保存表连接或聚集等耗时较多的操作的结果,这样,在执行查询时,就可以避免进行这些耗时的操作,从而快速的得到结果。物化视图有很多方面和索引很相似:使用物化视图的目的是为了提高查询性能;物化视图对应用透明,增加和删除物化视图不会影响应用程序中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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: