zoukankan      html  css  js  c++  java
  • mysql优化之物化视图

    物化视图

    概念

    物化视图是相对于视图而言的,但是两者实际上并没有什么关系就如java/javaScript一样

    首先mysql的视图不是一种物化视图,他相当于一个虚拟表,本身并不存储数据,当sql在操作视图时所有数据都是从其他表中查询出来的。

    者带来的问题是使用 视图并不能将常用数据分离出来,优化查询速度,且操作视图的很多命令和普通表一样,这回导致在业务中无法通过sql区分表和视图,是代码变得复杂。

    视图是简化设计,清晰编码的东西,他并不是提高性能的,他的存在只会降低性能(如一个视图7个表关联,另一个视图 8个表,程序员不知道,觉得很方便,把两个视图关联再做一个视图,那就惨了),他的存在未了在设计上的方便性。

    物化视图可以帮助加快严重依赖某些聚合结果的查询。

    如果插入速度不是问题,则此功能可以帮助减少系统上的读取负载。

    可以看出来数据量庞大的时候这个 时间...

    物化视图更新方式

    名称 描述
    从不更新 只在开始更新
    根据需要 每天,每夜
    及时 每次修改数据之后
    全部更新 速度慢,完全从无到有
    延时的 速度快,使用log表

    延迟更新与及时更新

    数据表

    结构

    CREATE TABLE `purchase_order` (
      `order_id` smallint NOT NULL AUTO_INCREMENT COMMENT '采购订单ID',
      `order_sn` varchar(30) DEFAULT '' COMMENT '单号 订单组号+仓库ID',
      `plan_id` smallint NOT NULL DEFAULT '0' COMMENT '计划ID',
      `group_id` int DEFAULT '0' COMMENT '订单组ID',
      `pro_num` int DEFAULT '0' COMMENT '商品总数',
      `pro_price` decimal(10,2) DEFAULT '0.00' COMMENT '商品总价',
      `pro_cat` smallint DEFAULT '0' COMMENT '商品种类',
      `supply_name` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`order_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3;
    

    数据

    延迟更新

    延迟更新特性:开销小,结果响应慢
    mysql实现方式:定时调用存储过程函数即可
    程序实现:定时计划处理
    

    mysql的实现方式

    文章表: id; 文章名; 作者名称;点击量;浏览量;文章内容

    1000w+ 查询点击量,浏览量,排名前五

    创建物化视图
    drop table purchase_mv; 
    CREATE TABLE purchase_mv( 
    supply_name VARCHAR(60) NOT NULL , 
    pro_count INT NOT NULL, 
    pro_price_sum INT NOT NULL, 
    pro_price_avg FLOAT NOT NULL, 
    pro_num_sum INT NOT NULL, 
    pro_num_avg FLOAT NOT NULL, 
    UNIQUE INDEX supply_name (supply_name) 
    );
    
    确定执行的查询语句
    SELECT 
        supply_name, 
        count(*) pro_count, 
        sum(pro_price) pro_price_sum, 
        avg(pro_price) pro_price_avg, 
        sum(pro_num) pro_num_sum, 
        avg(pro_num) pro_num_avg 
    from 
        purchase_order 
    group by supply_name;
    
    创建与物化视图相关视图
    create view por_view as 
    SELECT
        supply_name, 
        count(*) pro_count, 
        sum(pro_price) pro_price_sum, 
        avg(pro_price) pro_price_avg, 
        sum(pro_num) pro_num_sum, 
        avg(pro_num) pro_num_avg 
    from 
        purchase_order 
    group by supply_name;
    
    添加数据
    insert into purchase_mv select * from por_view
    

    按需更新物化视图

    根据需要更新物化视图,我们可以用存储过程来实现

    创建存储过程
    DROP PROCEDURE refresh_mv_now; 
    DELIMITER $$ 
    CREATE PROCEDURE refresh_mv_now () 
    BEGIN 
        TRUNCATE TABLE purchase_mv; 
        INSERT INTO purchase_mv SELECT * FROM por_view; 
    END; 
    $$DELIMITER ;
    
    最终测试
    INSERT INTO purchase_order (order_sn, `ctime`, supply_id, supply_name, pro_num, pro_price, shipping_state) VALUES ('C1803221553615160063su','1521701992', '1','友阿果园',75,479,2) 
    
    CALL refresh_mv_now(); 
    
    SELECT * FROM purchase_mv;
    

    及时更新

    特点

    及时更新特性:开销大,结果响应快 
    mysql实现方式:执行insert,update,delete,alter操作后执行触发器 
    程序实现:异步队列事件方式
    

    mysql实现方式

    在每个语句之后进行完全刷新是没有意义的。

    但我们仍然希望得到正确的结果。

    要做到这一点,要复杂一点。

    在purchase_order表上的每一个插入项上,我们都必须更新我们的物化视图。

    我们可以通过purchase_order表上的 INSERT/UPDATE/DELETE触发器透明地实现这一点:这里以isnert为列子

    思路:通过触发器,然后在添加完数据之后获取之前的聚合值的数据,然后根据新增的这条数据再做实时更新

    触发器实现
    after insert on drop trigger purchase_mv_trigger_ins; 
    
    DELIMITER $$ 
    CREATE TRIGGER purchase_mv_trigger_ins AFTER INSERT 
    ON purchase_order FOR EACH ROW 
    BEGIN 
        SET @old_pro_price_sum = 0; 
        SET @old_pro_price_avg = 0; 
        SET @old_pro_num_sum = 0; 
        SET @old_pro_num_avg = 0; 
        SET @old_pro_count = 0; 
    # 查询出之前的信息然后记录到不同的变量中 
        SELECT 
            IFNULL(pro_price_sum,0), 
            IFNULL(pro_price_avg,0), 
            IFNULL(pro_num_sum,0), 
            IFNULL(pro_num_avg,0), 
            IFNULL(pro_count,0) 
        FROM 
        purchase_mv 
        WHERE supply_name = NEW.supply_name 
        INTO
            @old_pro_price_sum,@old_pro_price_avg,@old_pro_num_sum,@old_pro_num_avg,@old_pro_count;
        # 然后再去计算更新操作之后的内容   
        SET @new_pro_count = @old_pro_count + 1;  
        SET @new_pro_price_sum = @old_pro_price_sum + NEW.pro_price; 
        SET @new_pro_price_avg = @new_pro_price_sum / @new_pro_count; 
        SET @new_pro_num_sum = @old_pro_num_sum + NEW.pro_num; 
        SET @new_pro_num_avg = @new_pro_num_sum / @new_pro_count; 
        REPLACE INTO 
            purchase_mv
         VALUES( 
            NEW.supply_name, @new_pro_count, 
            @new_pro_price_sum, IFNULL(@new_pro_price_avg, 0), 
            @new_pro_num_sum, IFNULL(@new_pro_num_avg, 0) ); 
    END; 
    $$DELIMITER ;
    
  • 相关阅读:
    OpenLayer学习之图文标注
    HTML5制作时钟(canvas)
    ADO,NET中简单三层SQLHelper封装介绍
    OpenLayer学习之加载天地图
    ArcGIS Server manger管理页面无法打开问题解决
    Java EE (14) -- SSH配置
    R语言实战读书笔记(一)R语言介绍
    Machine Learning for hackers读书笔记_一句很重要的话
    Machine Learning for hackers读书笔记(十二)模型比较
    Machine Learning for hackers读书笔记(十)KNN:推荐系统
  • 原文地址:https://www.cnblogs.com/studyandstudy/p/14698457.html
Copyright © 2011-2022 走看看