Derek Downey Asked: 2011-01-06 18:05:00 +0800 CST2011-01-06 18:05:00 +0800 CST 2011-01-06 18:05:00 +0800 CST MySQL 存储例程中的动态 SQL 772 根据存储过程和触发器的限制,不能使用动态sql(5.0.13及以后版本的存储过程限制解除)。为什么会有这个限制?为什么要为程序而不是函数或触发器取消它? mysql stored-procedures 3 个回答 Voted Best Answer RolandoMySQLDBA 2011-03-25T22:07:12+08:002011-03-25T22:07:12+08:00 光是听到这个问题,我就想到了两个方面: 方面#1:函数应该是确定性的 如果是这样,这意味着函数应该为给定的一组参数一致地呈现相同的返回数据,无论何时调用该函数。 现在,想象一个函数,由于基于函数中的静态 SQL 在一天中的不同时间收集数据而产生不同的答案。从某种意义上说,如果您每次都查询相同的表和列集,并且给定相同的参数集,那么这仍然可以被认为是确定性的。 如果您可以通过动态 SQL 更改函数的基础表会怎样?您违反了 DETERMINISTIC 函数的定义。 注意 MySQL 在 /etc/my.cnf 中添加了这个选项 log-bin-trust-function-creators 虽然这可能过于简单化了,但这允许函数将数据写入二进制日志,而无需严格执行 DETERMINISTIC 属性。 方面#2:触发器应该能够回滚 您能想象一个触发器具有与函数相同的所有行为,然后将动态 SQL 引入组合中吗? 您能想象在将 MVCC 应用于触发器的基表之后尝试针对动态 SQL应用MVCC(多版本并发控制)吗? 仅在 MVCC 中,您基本上就会拥有以二次方(甚至指数方式)增长的数据。至少可以说,使用可能是非确定性的触发器来管理 SQL 回滚的过程将非常复杂。 鉴于这两个方面,我敢肯定 MySQL 开发人员想到了这些事情,并通过施加限制迅速将它们排除在外。 那么,为什么要解除对程序的限制呢?简而言之,无需担心 DETERMINISTIC 属性或回滚。 jcolebrand 2011-01-06T19:07:31+08:002011-01-06T19:07:31+08:00 这是一个很好的问题,但我不知道答案。我想这将不得不转到内部团队,但我不知道他们会在这个网站上大放异彩。同时,我可以帮你推断出一些答案。 对于初学者,我看到了这个: 触发器缓存不会检测底层对象的元数据何时发生更改。如果触发器使用表并且自触发器加载到缓存中后表已更改,则触发器使用过时的元数据进行操作。 这让我觉得这与它有关。如果它甚至不监视元数据,它就不会重新编译 SQL。这意味着这是一个引擎问题。 出于同样的原因,当我阅读这个块时,我认为同样的事情(引擎): 为了防止服务器线程之间的交互问题,当客户端发出语句时,服务器使用可用于执行语句的例程和触发器的快照。也就是说,服务器计算在执行语句期间可能使用的过程、函数和触发器的列表,加载它们,然后继续执行语句。这意味着当语句执行时,它不会看到其他线程执行的例程的更改。 所以总而言之,我不完全确定他们为什么不允许这样做,但我可以猜到。抱歉,我无法为您提供更多帮助,我愿意进一步解决这个问题。最好的希望是一旦我们离开私人测试版,就会有一些活跃的 MySQL 开发人员;) dba4life 2011-03-26T08:37:39+08:002011-03-26T08:37:39+08:00 很大程度上是出于安全考虑。过程的例外是因为可以为过程中的动态 SQL 分配执行用户的安全上下文。这意味着即使引擎不知道将要执行什么,它也可以确保允许用户访问引用的对象。 除此之外,如果允许,您可以提出可能发生的丑陋问题。
光是听到这个问题,我就想到了两个方面:
方面#1:函数应该是确定性的
如果是这样,这意味着函数应该为给定的一组参数一致地呈现相同的返回数据,无论何时调用该函数。
现在,想象一个函数,由于基于函数中的静态 SQL 在一天中的不同时间收集数据而产生不同的答案。从某种意义上说,如果您每次都查询相同的表和列集,并且给定相同的参数集,那么这仍然可以被认为是确定性的。
如果您可以通过动态 SQL 更改函数的基础表会怎样?您违反了 DETERMINISTIC 函数的定义。
注意 MySQL 在 /etc/my.cnf 中添加了这个选项
虽然这可能过于简单化了,但这允许函数将数据写入二进制日志,而无需严格执行 DETERMINISTIC 属性。
方面#2:触发器应该能够回滚
仅在 MVCC 中,您基本上就会拥有以二次方(甚至指数方式)增长的数据。至少可以说,使用可能是非确定性的触发器来管理 SQL 回滚的过程将非常复杂。
鉴于这两个方面,我敢肯定 MySQL 开发人员想到了这些事情,并通过施加限制迅速将它们排除在外。
那么,为什么要解除对程序的限制呢?简而言之,无需担心 DETERMINISTIC 属性或回滚。
这是一个很好的问题,但我不知道答案。我想这将不得不转到内部团队,但我不知道他们会在这个网站上大放异彩。同时,我可以帮你推断出一些答案。
对于初学者,我看到了这个:
这让我觉得这与它有关。如果它甚至不监视元数据,它就不会重新编译 SQL。这意味着这是一个引擎问题。
出于同样的原因,当我阅读这个块时,我认为同样的事情(引擎):
所以总而言之,我不完全确定他们为什么不允许这样做,但我可以猜到。抱歉,我无法为您提供更多帮助,我愿意进一步解决这个问题。最好的希望是一旦我们离开私人测试版,就会有一些活跃的 MySQL 开发人员;)
很大程度上是出于安全考虑。过程的例外是因为可以为过程中的动态 SQL 分配执行用户的安全上下文。这意味着即使引擎不知道将要执行什么,它也可以确保允许用户访问引用的对象。
除此之外,如果允许,您可以提出可能发生的丑陋问题。