MySQL存储例程中的动态SQL

Der*_*ney 13 mysql trigger stored-procedures

根据存储例程和触发器限制,不能使用动态sql(5.0.13及以后版本的存储过程限制解除)。为什么会有这个限制?为什么将它提升为过程,而不是函数或触发器?

Rol*_*DBA 8

光听这个问题,我就想到了两个方面:

方面#1:函数应该是确定性的

如果是这样,这意味着函数应该为给定的参数集一致地呈现相同的返回数据,无论何时调用该函数。

现在,假设一个函数会根据函数中的静态 SQL 在一天中的不同时间收集数据,从而产生不同的答案。从某种意义上说,如果您每次查询相同的一组表和列,给定相同的参数组,那仍然可以被认为是 DETERMINISTIC。

如果您可以通过动态 SQL 更改函数的基础表会怎​​样?您违反了 DETERMINISTIC 函数的定义。

注意 MySQL 在 /etc/my.cnf 中添加了这个选项

log-bin-trust-function-creators
Run Code Online (Sandbox Code Playgroud)

尽管这样说可能过于简单化,但这允许允许函数将数据写入二进制日志,而无需严格执行 DETERMINISTIC 属性。

方面#2:触发器应该能够回滚

  • 您能想象一个触发器具有与函数相同的所有行为,然后将动态 SQL 引入到组合中吗?
  • 您能想象在将 MVCC 应用于触发器所针对的基表后,尝试对动态 SQL应用MVCC(多版本并发控制)吗?

仅在 MVCC 中,您基本上就会拥有二次(甚至指数)增长的数据。至少可以说,使用可能是非确定性的触发器来管理 SQL 回滚的过程将非常复杂。

鉴于这两个方面,我相信 MySQL 开发人员想到了这些事情,并通过施加限制迅速将其驳回。

那么,为什么要取消对程序的限制呢?简而言之,无需担心 DETERMINISTIC 属性或回滚。

  • 如果其他 DBMS 可以很好地支持触发器中的 MVCC 和动态 SQL,那么就不会如此“非常复杂”。 (3认同)

jco*_*and 5

这是一个很好的问题,但我不知道答案。我想这将不得不转交给内部团队,但我不知道他们会对这个网站有多大影响。同时,我可以帮你推导出一些答案。

对于初学者,我看到了这一点:

触发器缓存不会检测底层对象的元数据何时发生更改。如果触发器使用一个表并且该表在触发器加载到缓存中后发生了变化,那么触发器将使用过时的元数据进行操作。

这让我觉得这与它有关。如果它甚至不监视元数据,它就不会重新编译 SQL。这意味着这是一个引擎问题。

出于同样的原因,当我阅读这个块时,我认为同样的事情(引擎):

为防止服务器线程之间的交互问题,当客户端发出语句时,服务器使用可用于执行语句的例程和触发器的快照。也就是说,服务器计算在语句执行期间可能使用的过程、函数和触发器的列表,加载它们,然后继续执行语句。这意味着当语句执行时,它不会看到其他线程执行的例程的更改。

所以总而言之,我不完全确定他们为什么不允许这样做,但我可以猜到。对不起,我不能帮到你更多,我愿意再多研究一下。最好是在我们离开私人测试版后希望有一些活跃的 MySQL 开发人员;)