从很早开始,MySQL就支持用户自定义函数(UDF)。存储过程只能使用SQL来编写,而UDF没有这个限制,你可以使用支持C语言调用约定的任何编程语言来实现。
UDF必须事先编译好并动态链接到服务器上,这种平台相关性使得UDF在很多方面都很强大。UDF速度非常快,而且可以访问大量操作系统的功能,还可以使用大量库函数。使用SQL实现的存储函数在实现一些简单操作上很有优势,诸如计算球体上两点之间的距离,但是如果操作涉及到网络交互,那么只能使用UDF了。同样地,如果需要一个MySQL不支持的统计聚合函数,而且无法使用SQL编写的存储函数来实现的话,通常使用UDF是很容易实现的。
能力越大,责任越大。所以在UDF中的一个错误很可能会让服务器直接崩溃,甚至扰乱服务器的内存或者数据,另外,所有C语言具有的潜在风险,UDF也都有。
提示:和使用SQL语言编写存储程序不同,UDF无法读写数据表——至少,无法在调用UDF的线程中使用当前事务处理的上下文来读写数据表。这意味着,它更适合用作计算或者与外面的世界交互。MySQL已经支持越来越多的方式和外面的资源交互了。Brian Aker和Patrick Galbraith创建的与memcached通信的函数就是一个UDF很好的案例。
如果打算使用UDF,那么在MySQL版本升级的时候需要特别注意做相应的改变,因为很可能需要重新编译这些UDF,或者甚至需要修改UDF来让它能在新的版本中工作。还需要注意的是,你需要确保UDF是线程安全的,因为它们需要在MySQL中执行,而MySQL是一个纯粹的多线程环境。
现在已经有很多写好的UDF直接提供给MySQL使用,还有很多UDF的示例可供参考, 以便完成自己的UDF。现在UDF最大的仓库是http://www.mysqludf.org。
下面是一个用户自定义函数NOW_USEC()的代码:
#include <my_global.h> #include <my_sys.h> #include <mysql.h> #include <stdio.h> #include <sys/time.h> #include <time.h> #include <unistd.h> extern "C" { my_bool now_usec_init(UDF_INIT *initid, UDF_ARGS *args, char *message); char *now_usec( UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error); } my_bool now_usec_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { return 0; } char *now_usec(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) { struct timeval tv; struct tm* ptm; char time_string[20]; /* e.g. "2006-04-27 17:10:52" */ char *usec_time_string = result; time_t t; /* Obtain the time of day, and convert it to a tm struct. */ gettimeofday (&tv, NULL); t = (time_t)tv.tv_sec; ptm = localtime (&t); /* Format the date and time, down to a single second. */ strftime (time_string, sizeof (time_string), "%Y-%m-%d %H:%M:%S", ptm); /* Print the formatted time, in seconds, followed by a decimal point * and the microseconds. */ sprintf(usec_time_string, "%s.%06ld\n", time_string, tv.tv_usec); *length = 26; return(usec_time_string); }
参考前一章中的案例学习,可以看到如何使用用户自定义函数来解决一些棘手的问题。在Percona Toolkit中也使用了UDF来完成一些工作,例如髙效的数据复制校验,或者在Sphinx索引之前使用UDF来预处理一些问题等。UDF是一款非常强大的工具。