MySQL存储过程与函数,我会在什么时候使用?

时间:2010-09-19 01:43:29

标签: mysql stored-procedures sql-function

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

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

我可能错了,但似乎存储过程可以做所有事情,而存储功能可以做得更多。为什么/何时使用程序与函数?

6 个答案:

答案 0 :(得分:241)

程序和功能之间最普遍的区别在于它们的调用方式不同且用途不同:

  1. 过程不返回值。而是使用CALL语句调用它来执行操作,例如修改表或处理检索到的记录。
  2. 在表达式中调用函数,并将单个值直接返回给调用者,以便在表达式中使用。
  3. 您不能使用CALL语句调用函数,也不能在表达式中调用过程。
  4. 例程创建语法对于过程和函数有所不同:

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

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

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

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

      如果在参数名称之前没有给出关键字,则默认情况下它是IN参数。 存储函数的参数前面没有IN,OUT或INOUT。所有函数参数都被视为IN参数。

    3. 要定义存储过程或函数,请分别使用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(将语句构造为字符串然后执行它们)。 (Dynamic SQL in MySQL stored routines)

      FUNCTION和STORED PROCEDURE之间的一些更有趣的区别:

      1. 这一点是copied from a blogpost) 存储过程是预编译的执行计划,而功能则不是。函数在运行时解析和编译。存储过程,存储为数据库中的伪代码,即编译形式。

      2. 我不确定这一点。
        存储过程具有安全性并减少网络 流量,我们也可以在任何号码中调用存储过程。的 一次申请。 reference

      3. 函数通常用于as的计算 程序通常用于执行业务逻辑。

      4. 功能不能影响数据库的状态 (在函数中不允许执行显式或隐式提交或回滚的语句) 而 存储过程可以使用提交等方式影响数据库的状态 参考:J.1. Restrictions on Stored Routines and Triggers

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

      6. 存储函数不能递归,而存储过程可以。 注意:默认情况下禁用递归存储过程,但可以通过将max_sp_recursion_depth服务器系统变量设置为非零值在服务器上启用。有关详细信息,请参阅Section 5.2.3, “System Variables”

      7. 在存储的函数或触发器中,不允许修改已经使用的表 (用于读取或写入)由调用函数或触发器的语句。 好例子:How to Update same table on deletion in MYSQL?

      8. 注意:虽然某些限制通常适用于存储的函数和触发器但不适用于存储过程,但如果从存储的函数或触发器中调用存储过程,则这些限制适用于存储过程。例如,虽然您可以在存储过程中使用FLUSH,但是无法从存储的函数或触发器调用此类存储过程。

答案 1 :(得分:92)

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

e.g。如果SELECT get_foo(myColumn) FROM mytable是一个过程,则get_foo()无效,但如果get_foo()是一个函数,则可以执行此操作。价格是函数比程序有更多限制。

答案 2 :(得分:49)

一个重要区别是您可以在SQL查询中包含function,但stored procedures只能使用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)

答案 3 :(得分:8)

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

使用CALL查询执行过程。

答案 4 :(得分:0)

存储过程可以递归调用,但是存储函数不能

答案 5 :(得分:0)

除了上面给出的答案,我想补充一下

函数可以与其他函数和表达式结合使用,也可以嵌套使用(简而言之,它们可以以非常复杂的形式使用,以完成我们想要的工作)。

同样的事情可以在程序中实现,但在程序中我们必须完成在该程序内完成的所有工作,这意味着在一个整体的时尚代码中。 (而 in 函数可以用于每个任务;可以实现一个新函数)。所以最后我们可以通过使用不同功能的组合来完成任务。