将引用计数合并到每个数据库表中是一个好主意吗?

时间:2009-12-30 15:09:33

标签: database database-design release

从Objective-C我习惯于引用计数/保留计数(同样的事情)。我喜欢这个概念,而且很简单。

所以我想,为什么不将它应用到数据库?问题是:

想象一下这些表:用户,照片。用户可以拥有照片,用户可以喜欢他自己或其他人的照片,并且用户可以推荐照片。无论如何,都会为照片创建一个参考。

现在最大的问题是:让我们说我想摆脱任何属于无人的照片。因此,不被任何用户拥有的照片不被任何用户所喜欢,并且不被任何用户推荐,必须被删除。我有没有想法如何使用普通的数据库功能;)好吧,可能有几百个连接?我不知道。数据库noob。

所以我想从数据库专家那里验证这个想法:想象一下我在每个可以引用的表中添加一个reference_count字段(当然需要一些设想)。一旦我定义了从table_a到任何table_b的关系,并且table_a应该是父或master(强引用),我将链接行的reference_count增加1。

假设150个用户喜欢照片,而其中一个拥有它。所以它的reference_count是151.现在主人放弃了,但是其他150人仍在尖叫“哦,不,不,不,不是!这是我们的!我们喜欢它如此muuucch !!”。系统通过所有这些表每隔午夜查看一次,并尝试删除引用计数为0的每一行。所以在几天之后,用户会对它感到厌倦并删除它们的“我喜欢它”标志。每次发生这种情况时,reference_count减少1.最后,它为0,并且在每个人都睡着的下一个午夜,一个cron作业删除它。

当然,它必须是可配置的,因为在没有人再引用照片之后必须永远不会删除照片。我会通过将它的reference_count最初设置为1而不是0来解决这个问题。

这当然意味着很多额外的db调用。所以你怎么看?或者有更好的解决方案吗?

8 个答案:

答案 0 :(得分:4)

您可以执行以下操作:

DELETE
FROM    photos
WHERE   id NOT IN
        (
        SELECT  photo_id
        FROM    photos_users_like
        )
        AND id NOT IN (
        SELECT  photo_id
        FROM    photos_users_made
        )
        AND id NOT IN (
        SELECT  photo_id
        FROM    photos_users_recommended
        )

如果您在所有表中对photo_ids编制索引,NOT IN将由MySQL进行优化,以便在引擎找到但是单个时谓词将返回FALSE在相应的表中匹配记录,并且不需要引用计数。

答案 1 :(得分:3)

通常使用

解决此问题
  1. 支持孤儿删除的ORM层,或
  2. 删除孤儿的数据库触发器
  3. 使用引用计数可能很昂贵,具体取决于数据修改的频率,并且可能会使您的数据库代码模糊不清,难以理解。

答案 2 :(得分:1)

您无需保留引用计数。我建议这样做。按照您的描述,您可以使用以下数据库结构:

create table users ( 
    id    int             not null auto_increment
,   name  varchar(64)     not null 
   ...more columns...
,   primary key (id)
)

create table photos ( 
    id             int          not null auto_increment
,   url            varchar(255) not null 
,   user_id_owner  int
,   primary key (id)
,   foreign key (user_id_owner) references users(id)
)

create table user_likes_photo (
    user_id  int not null
,   photo_id int not null
,   primary key(user_id, photo_id)
,   foreign key (user_id)  references users(id)
,   foreign key (photo_id) references photos(id)
)

create table user_recommends_photo (
    user_id_recommending  int not null
,   photo_id              int not null
,   user_id_recommended   int not null
,   primary key(user_id_recommending, photo_id, user_id_recommended)
,   foreign key (user_id_recommending)  references users(id)
,   foreign key (user_id_recommended)   references users(id)
,   foreign key (photo_id) references photos(id)
)

这样,您可以跟踪所有关系。

要删除未提及的照片,请执行以下操作:

delete from photos
where user_id_owner is null 
and id not in (
    select photo_id
    from   user_likes_photo
)
and id not in (
    select photo_id
    from   user_recommends_photo
)

答案 3 :(得分:1)

参考计数不一定是必要的;大多数数据库都会为您跟踪关系完整性

例如,如果你执行了

,则在ms-sql中
delete from photos where photoid = 1234

但该照片在某处被引用,数据库将引发错误并拒绝删除照片;在.NET代码中,这表现为Sql异常

如果您需要提前知道是否可以删除照片,上述EXISTS查询将有效;如果你不需要事先知道,那就试着删除它,让数据库告诉你,你不能

引用计数是额外工作的很多,可能是不必要的;在这方面利用数据库的功能

答案 4 :(得分:0)

我认为这是级联删除的目的。我不赞成这样做。对于非垃圾收集语言,引用计数是一个好主意,但在这种情况下,我认为SQL已经覆盖了很长时间。

这就是拥有数据库管理员的好处。 Noobs往往会陷入困境。

答案 5 :(得分:0)

要查找没有人拥有的照片,您可以执行以下操作:

select P.PhotoId
  from Photos as P
  where not exist (select ownerId from PhotoOwners as PO where PO.PhotoId = P.PhotoId)

这可以扩展到任意数量的不存在检查。

为防止删除引用的照片,您可以使用外键。

总结:RDBMS旨在解决这些类型的问题,而无需引用计数和每个应用程序构建的其他(易出错)机制。

答案 6 :(得分:0)

无聊的用户不太可能不费力地扭转之前的upvote。为什么不计算一个更直接有用的指标,比如上个月的综合浏览量?

答案 7 :(得分:0)

“在这方面利用数据库的功能”

阿门。

并且其逻辑上的结论是“如果另一个DBMS在这方面具有更多功能,那么立即切换到该DBMS”。