使用git语义的数据库表的最佳模式?

时间:2016-01-05 18:11:12

标签: database postgresql nosql

我们有一些中等到大的表(即数百行的数据)我们希望用户能够有效地使用#fork;#34;与Git类似,并可能随着时间的推移进行协作。我们希望他们能够" fork"它们多次,并对不同的叉子进行编辑,并比较两个叉子之间的各种聚合数据。

基本上,这些数据以一组只读表开始,我们希望让用户能够查看包含其编辑的表。我们面临的挑战是,我们还要定期查询此表中的行(即仅显示column3 =' left')的行,甚至可能根据特定列连接另一个表。 (即INNER JOIN,其中user_table.column3 = other_table.column10) - 即我们希望能够将这些表视为关系操作的完全物化表。

最愚蠢的解决方案(我们今天做的)只是制作表格的完整副本,但挑战是至少在我们目前的版本中这是昂贵的:我们使用PostgreSQL,这些复制操作可以采取2- 20分钟。我们希望这是一个实时操作,就像具有写时复制行为的东西一样。

我们会记录用户所做的更改(即更改日志),以便我们最终将它们应用于"原始"表格,但有一个模式,或理想的世界,图书馆或存储层,这只是为我们这样做。

我们今天碰巧使用PostgreSQL和Python,但我在这里对NoSQL系统开放,因为我可以想象这可能导致一些非常讨厌的SQL,如果这足够概括的话。此外,我们愿意牺牲一些关系能力来实现上述目标。这个领域是否有已知的模式和/或实现?在PostgreSQL或其他存储系统中?事实证明这对谷歌来说真的很难。

1 个答案:

答案 0 :(得分:1)

当然可以使用它做一些事情,虽然结果可能(或可能不)是片状的,这取决于你将在数据库中使用多少其他黑客。

如果我们将列ownerdeleted添加到源表中,请创建一个视图,向视图添加INSTEAD OF个触发器,并仅向视图授予用户权限,而不是源表我们得到这个:

CREATE SEQUENCE source_seq;
CREATE TABLE source
(
    id INT DEFAULT nextval('source_seq')
    ,value VARCHAR
    ,owner name DEFAULT session_user
    ,deleted boolean DEFAULT FALSE
);
CREATE VIEW source_emp AS
    SELECT id, value
    FROM source AS s1
    WHERE ((owner IS NULL AND NOT EXISTS (SELECT * FROM source AS s2 WHERE s1.id = s2.id AND s2.owner = session_user )) OR owner = session_user)
    AND NOT deleted
CREATE OR REPLACE FUNCTION source_change()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
   BEGIN      
      IF TG_OP = 'UPDATE' THEN
       INSERT INTO source(id,value,owner,deleted) 
       SELECT NEW.id,NEW.value,session_user, FALSE
       WHERE NOT EXISTS(SELECT * FROM source WHERE owner = session_user AND id = OLD.id);
       UPDATE source SET id = NEW.id, value = NEW.value, owner = session_user WHERE owner = session_user AND id = OLD.id;              
       RETURN NEW;
       ELSIF TG_OP = 'DELETE' THEN
       INSERT INTO source(id,value,owner,deleted) 
       SELECT OLD.id,NULL,session_user, TRUE
       WHERE NOT EXISTS(SELECT * FROM source WHERE owner = session_user AND id = OLD.id);
       UPDATE source SET value = NULL, deleted = TRUE WHERE owner = session_user AND id = OLD.id;
       RETURN NULL;
      END IF;
      RETURN NEW;
    END;
$function$;

CREATE TRIGGER source_trig
    INSTEAD OF UPDATE OR DELETE ON
      source_emp FOR EACH ROW EXECUTE PROCEDURE source_change();

现在,如果用户尝试:

  • INSERT:他获取只在视图中可见的记录
  • 更新:他获得了原始记录的副本并编辑了这些记录或更新了他的副本
  • 删除:他将标记为已删除的来源仅供个人使用。

如果您不想触摸原始表格,您可以使用其他两列创建一个新表格并更改视图,使其与原始表格结合使用。