物化视图未更新

时间:2018-11-08 11:49:28

标签: sql postgresql migration knex.js materialized-views

我有一个物化视图,基本上可以跟踪结帐时使用的所有凭证,因此我可以跟踪已使用的凭证,剩余的数量等。我只是注意到,物化视图不会更新,目前显示以下内容:

enter image description here

left随使用凭证而明显减少的地方(凭证类型和使用凭证以及使用凭证的用户ID在不同的表中)。但是,它检测到已使用了一张凭证,但至于我在测试中使用的另外2张凭证,则不会从存储已使用凭证的表中拾取它们并更新MV。

这是我目前制作MV所要进行的迁移的一部分:

exports.up = function(knex, Promise) {
  return knex.schema
  .raw(`
  CREATE MATERIALIZED VIEW mv_vouchers as
  SELECT v.voucher_id, v.quantity, COUNT(ov.voucher_id) AS "used", v.quantity - COUNT(ov.voucher_id) AS "left"
  FROM public.vouchers v LEFT OUTER JOIN
       public.order_vouchers ov
       ON v.voucher_id = ov.voucher_id
  GROUP BY v.voucher_id, v.quantity;
  `);
};

我觉得我没有正确使用物化视图,并且只在迁移中运行了一次查询(当我最初实现mv时)。

EDIT

有关其他信息,这里是我拥有的另外两个表:

优惠券:

enter image description here

order_vouchers:

enter image description here

2 个答案:

答案 0 :(得分:2)

MV基本上只是一个表,除了它还记得应该执行哪个查询以更新(实际上是替换)其内容。

我认为Postgres没有任何parameter for automatically refreshing the MV,无论是实时的还是定期的。

创建视图时将查询并存储数据,除非您指定WITH NO DATA,否则将创建为空。

然后您可以通过调用REFRESH MATERIALIZED VIEW来按需(重新)填充视图。

答案 1 :(得分:0)

只是想我会为此添加一个快速解决方案:

exports.up = function(knex, Promise) {
  return knex.schema
  .raw(`
  CREATE MATERIALIZED VIEW mv_vouchers as
  SELECT v.voucher_id, v.quantity, COUNT(ov.voucher_id) AS "used", v.quantity - COUNT(ov.voucher_id) AS "left"
  FROM public.vouchers v LEFT OUTER JOIN
       public.order_vouchers ov
       ON v.voucher_id = ov.voucher_id
  GROUP BY v.voucher_id, v.quantity;
  `)
  .raw(`
      CREATE FUNCTION refresh_mv_vouchers() RETURNS trigger LANGUAGE plpgsql AS $$
        BEGIN
          REFRESH MATERIALIZED VIEW CONCURRENTLY mv_vouchers;
          RETURN null;
        END $$;
    `)
    .raw(`
      CREATE TRIGGER refresh_mv_vouchers
        AFTER insert OR update OR delete OR truncate
        ON order_vouchers
        EXECUTE PROCEDURE refresh_mv_vouchers();
    `);
};

exports.down = function(knex, Promise) {
  return knex.schema
    .raw('DROP MATERIALIZED VIEW mv_vouchers')
    .raw('DROP TRIGGER refresh_mv_vouchers ON order_vouchers')
    .raw('DROP FUNCTION refresh_mv_vouchers()');
};

比我最初想象的要直接得多。