“黑洞”表是一种邪恶的表吗?

18

阅读这个问题,我刚刚学到了blackhole表技巧的存在:基本上是使用一个单一的表来插入数据,然后使用触发器将数据拆分成许多其他表。

我在想,一旦正在项目上工作的开发人员知道了这一点,是否会引起问题。

这种技巧的利弊是什么?

编辑:我想到的问题是事务:如果由于某些原因事务失败,您将在blackhole行中找到原始数据,以便进行历史记录和可能帮助调试 - 但这似乎是我看到黑洞时唯一的优点。有什么想法吗?


作为一种事务日志,大多数数据库不容易读取事务日志。良好的事务日志管理并非易事。理想情况下,每行更新都应该有其之前和之后的记录。这会导致事务日志迅速增长。黑洞模式仅捕获插入操作。 - MatthewMartin
3
我会点赞,因为你让我意识到了另一种令人恐惧的做法。 - bevacqua
8个回答

18

我认为黑洞没有任何真正的优点。

编写触发器代码来移动数据的工作量可能与一开始就将数据插入正确位置的代码相比几乎没有差别。

正如Christian Oudard所写,它不会减少复杂性,只是把它移到一个很难调试的地方。

缺点是:

“副作用”通常在软件开发中是个坏主意。触发器就是副作用-我打算做一件事(在表中插入数据),但它实际上会做许多其他事情。现在,当我调试我的代码时,我还必须记住所有的副作用 - 而这些副作用本身可能又有副作用。

大多数软件花费的时间都在维护而不是开发方面。将新的开发人员引入团队并解释黑洞技巧可能会增加学习曲线-对于微不足道的好处(在我的看法中)。

因为触发器是副作用,如果不小心设置,很容易引发大规模触发级联效应,因此我总是尝试设计自己的数据库,而不依赖触发器;在触发器显然是正确的方法时,我只允许最有经验的开发人员创建它们。黑洞技巧将触发器变成一种正常、常规的工作方式。当然,这是个人的观点。


+1。实际上它可能没有专业人士,只有业余爱好者 :-)。(这个笑话在于法语单词“amateur”的意思,它的意思类似于“支持者”。) - Erwin Smout
1
@Erwin - 这个笑话用中文也行,基本上表达的意思是“没有好的观点,只有热情洋溢的初学者”,这暗示了这些人不知道自己在做什么。 - Drew
如果您正在测量数据库驱动程序的性能,并希望将性能数字与服务器时间分离,则此功能非常有用。不幸的是,其他SQL服务器没有这个很棒的功能。 - Nikhil

16

引发你问题的原始问题并没有涉及到MySQL中“黑洞”的本质。

什么是BLACKHOLE?

在MySQL中,BLACKHOLE是一种存储引擎,它会简单地丢弃插入其中的所有数据,类似于一个空设备。使用这种后端的理由有很多,但它们往往有点深奥:

  • “只继承”binlog过滤从服务器
    参见文档以及这里这里
  • 基准测试
    例如,测量二进制日志记录开销而不担心存储引擎开销
  • 各种计算技巧
    参见这里

如果您不知道为什么需要一个伪装成表的数据接收器,请不要使用它。

你所询问的技术是什么?

考虑中的用途似乎是:

  1. 将插入的数据重定向到其他表
  2. 审计日志原始的插入操作
  3. 丢弃原始的插入数据
因此,“邪恶性”或优劣的答案与插入/可更新视图(实现#1的常见方式)、基于触发器的审计日志记录(大多数人执行#2的方式)以及通常的行为覆盖/抵消(有多种方法可以完成#3)的答案相同。
那么,答案是什么呢?当然,“有时这些技术是适当的,有时则不是。” :) 您是否知道自己在做什么?应用程序是否更适合此功能?抽象化是否过于脆弱、泄漏、僵化等?

4

这似乎不是一个好主意。如果你想让前端代码保持简单,为什么不直接使用存储过程?如果不是为了保持前端代码简单,我根本就不理解它的意义所在。


3
有趣的是,今天我也了解到黑洞的存在。
可以说,这里的问题实际上更广泛,即业务逻辑是否应该嵌入数据库触发器中。在这种情况下,黑洞表实际上被用作一个暂时的数据存储器,黑洞表上的触发器可以利用它。首先应该使用触发器吗?对我来说,这才是问题的真正核心。
个人认为,触发器的使用应该仅限于日志记录和DBA特定任务,并且不应包含属于应用程序层的业务逻辑(或任何逻辑)。似乎已经有很多意见表达了数据库触发器是否邪恶。我认为你的问题也属于这个范畴。
在数据库触发器中嵌入应用程序层逻辑可能会带来风险。
它很可能会将业务逻辑分割在应用程序代码和数据库之间。这对于试图支持和理解代码库的人来说可能非常令人困惑。
如果触发器和存储过程中的逻辑过多,您的数据库服务器可能会出现性能问题,这些问题本应由应用服务器分担处理任务,例如将复杂的业务逻辑分散在应用服务器中,以使数据库服务器保持空闲状态,专注于其主要任务即提供数据服务。
当然,这只是我的一点建议!

2
每次向表中插入一行数据时,很可能会写入硬盘的同一区域或同一页(在MS-SQL世界中,我不知道PostgreSQL),因此这种技术很可能会导致争用和锁定,因为所有事务现在都竞争写入同一个表。此外,这将使插入性能减半,因为需要进行两次插入而不是一次。同时这也是反规范化的,因为现在有两份数据副本而不是一份。

性能是一个很好的点,但在这种情况下去规范化可能用于“历史”目的...我这次不认为这是坏事。 - Strae
5
自从 1970 年代以来,我一直从事数据库工作,这可能是我听过的关于数据库设计最糟糕的想法。你为了数据完整性、性能和安全性而设计数据库,而不是为了让应用程序开发人员更容易。通常情况下,用户会每分钟插入记录多次,而开发人员仅在数年内偶尔修改该部分代码。这将是性能上的噩梦。除非只有两个用户并且几乎没有插入,否则这种方法永远无法在负载下正常运行。 - HLGEM
@daniel,如果你想要历史记录,请使用审计表,但是不要为所有的表都使用一个审计表,因为这会影响性能。 - HLGEM
@HLGEM 目前我正在使用日志(大多数是基于文件的)进行历史记录,这是应该的,但是...好吧,这种技术只是在我的脑海中点亮了一个灯泡 ;) - Strae

1
请不要这样做。这并没有减少复杂性,只是把它转移了。这种逻辑应该放在应用层中,在那里您可以使用更好的语言,如PHP、Python或Ruby来实现它。

1

不要这样做。它被称为技巧而不是标准方法已经足够说明问题了。

这完全破坏了关系模型的正常使用模式。不确定它是否真的破坏了正常形式,因为你仍然可以保持所有的东西。它只是干扰了数据到达目标表的方式。看起来像是性能和维护上的噩梦。例如,想象一张表有一个触发器,必须为1800多个表插入操作触发。这让我感到恶心。

这只是一个有趣的花招,没有其他意义。


0
我认为这会相当慢,因为无法利用“批量插入”的优势。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接