MySQL存储过程与函数,何时使用?


160

我正在查看MySQL存储过程和函数。真正的区别是什么?

它们似乎相似,但是功能有更多限制。

我可能错了,但似乎存储过程可以完成所有工作,而存储函数可以完成更多工作。为什么/何时使用过程与函数?

Answers:


101

不能将存储过程与普通SQL混合使用,而可以将存储函数与普通SQL混合使用。

例如,SELECT get_foo(myColumn) FROM mytable如果get_foo()是一个过程,则无效,但如果get_foo()是一个函数,则可以这样做。代价是功能比程序具有更多的限制。


18
函数有哪些限制?
Fantius 2011年

11
嗯,我发现了一些很好的信息在这里: dev.mysql.com/doc/refman/5.0/en/...
Fantius

262

过程和函数之间最普遍的区别是,它们以不同的目的和不同的目的被调用:

  1. 过程不返回值。而是使用CALL语句调用它来执行诸如修改表或处理检索到的记录之类的操作。
  2. 在表达式中调用一个函数,然后将单个值直接返回给要在表达式中使用的调用方。
  3. 您不能使用CALL语句调用函数,也不能在表达式中调用过程。

例程创建的语法在过程和功能上有所不同:

  1. 可以将过程参数定义为仅输入,仅输出或两者。这意味着过程可以使用输出参数将值传递回调用方。可以在CALL语句之后的语句中访问这些值。函数仅具有输入参数。结果,尽管过程和函数都可以具有参数,但是过程参数声明与函数的声明不同。
  2. 函数返回值,因此函数定义中必须有RETURNS子句,以指示返回值的数据类型。此外,函数体内必须至少有一个RETURN语句才能将值返回给调用方。RETURNS和RETURN不会出现在过程定义中。

    • 要调用存储过程,请使用CALL statement。要调用存储的函数,请在表达式中引用它。该函数在表达式求值期间返回一个值。

    • 使用CALL语句调用过程,并且只能使用输出变量传回值。可以像其他任何函数一样从语句内部调用函数(即,通过调用函数名称),并且可以返回标量值。

    • 将参数指定为IN,OUT或INOUT仅对PROCEDURE有效。对于功能,参数始终被视为IN参数。

    如果在参数名称之前未提供关键字,则默认情况下为IN参数。 用于存储功能的参数之前没有IN,OUT或INOUT。所有功能参数均视为IN参数。

要定义存储过程或函数,请分别使用CREATE PROCEDURE或CREATE FUNCTION:

CREATE PROCEDURE proc_name ([parameters])
 [characteristics]
 routine_body


CREATE FUNCTION func_name ([parameters])
 RETURNS data_type       // diffrent
 [characteristics]
 routine_body

MySQL对存储过程(不是函数)的扩展是,一个过程可以生成一个结果集,甚至多个结果集,调用者以与SELECT语句的结果相同的方式对其进行处理。但是,此类结果集的内容不能直接在表达式中使用。

存储例程(既指存储过程又指存储函数)与特定的数据库相关联,就像表或视图一样。删除数据库时,数据库中所有已存储的例程也会被删除。

存储过程和函数不共享相同的名称空间。在数据库中可能有一个具有相同名称的过程和函数。

在存储过程中,可以使用动态SQL,但不能在函数或触发器中使用。

SQL预准备语句(PREPARE,EXECUTE,DEALLOCATE PREPARE)可以在存储过程中使用,但不能用于存储函数或触发器。因此,存储的函数和触发器不能使用动态SQL(将语句构造为字符串然后执行它们)。(MySQL中的动态SQL存储例程)

功能和存储过程之间还有一些更有趣的区别:

  1. 这是从博客文章中复制的)存储过程是预编译的执行计划,而函数没有。在运行时解析和编译的函数。存储过程,作为伪代码存储在数据库中,即编译形式。

  2. 我不确定这一点。
    存储过程具有安全性并减少了网络流量,而且我们可以以任何方式调用存储过程。一次申请。参考

  3. 函数通常用于计算,而过程通常用于执行业务逻辑。

  4. 函数不能影响数据库的状态(函数中不允许进行显式或隐式提交或回滚的语句),而存储过程可以使用提交等来影响数据库的状态。
    参考:J.1。对存储的例程和触发器的限制

  5. 函数不能使用FLUSH语句,而存储过程可以。

  6. 存储函数不能是递归的,而存储过程可以是递归的。注意:递归存储过程默认情况下处于禁用状态,但是可以通过将max_sp_recursion_depth服务器系统变量设置为非零值来在服务器上启用。有关更多信息请参见第5.2.3节“系统变量”

  7. 在存储的函数或触发器内,不允许修改调用该函数或触发器的语句已在使用(用于读取或写入)的表。很好的例子:如何在MYSQL中删除时更新同一张表?

注意:尽管一些限制通常适用于存储函数和触发器,但不适用于存储过程,但是如果从存储函数或触发器中调用它们,则这些限制确实适用于存储过程。例如,尽管可以在存储过程中使用FLUSH,但是不能从存储函数或触发器中调用这种存储过程。


2
@GrijeshChauhan,当您说“在运行时解析并编译函数”时,您是什么意思?
和平者

@Pacerier意味着MySQL中的函数就像是那些可以即时编译和执行的脚本。我从某篇博客文章中复制了该文章,但没有进行任何实际操作来检查此行为。
Grijesh Chauhan

在过程中,您可以传递out变量作为参数,然后使用select语句调用它
LTroya

1
我认为,此答案底部的第4点是程序和功能之间差异的核心。程序可以更改数据库,功能不能。所有其他差异只是为了更有效地达到该目的。
Woodrow Barlow

51

一个重要的区别是您可以在SQL查询中包括一个函数,但是存储过程只能用以下CALL语句调用:

UDF示例:

CREATE FUNCTION hello (s CHAR(20))
   RETURNS CHAR(50) DETERMINISTIC
   RETURN CONCAT('Hello, ',s,'!');
Query OK, 0 rows affected (0.00 sec)

CREATE TABLE names (id int, name varchar(20));
INSERT INTO names VALUES (1, 'Bob');
INSERT INTO names VALUES (2, 'John');
INSERT INTO names VALUES (3, 'Paul');

SELECT hello(name) FROM names;
+--------------+
| hello(name)  |
+--------------+
| Hello, Bob!  |
| Hello, John! |
| Hello, Paul! |
+--------------+
3 rows in set (0.00 sec)

Sproc示例:

delimiter //

CREATE PROCEDURE simpleproc (IN s CHAR(100))
BEGIN
   SELECT CONCAT('Hello, ', s, '!');
END//
Query OK, 0 rows affected (0.00 sec)

delimiter ;

CALL simpleproc('World');
+---------------------------+
| CONCAT('Hello, ', s, '!') |
+---------------------------+
| Hello, World!             |
+---------------------------+
1 row in set (0.00 sec)

1
您的函数有两个返回?我的意思是这条线是什么?RETURNS CHAR(50) DETERMINISTIC
马丁AJ

RETURNS CHAR(50)什么类型的数据的状态将被退回。该RETURN CONCAT(...是正在返回的数据。两者都需要。的DETERMINISTIC是需要状态下的基础数据也不会被修改。
lemming622 '19

8

可以在查询中使用存储的函数。然后,您可以将其应用于每一行或WHERE子句中。

使用CALL查询执行过程。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.