建立 MySQL 用戶自定義函數 (UDF) 時常遇到 This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA... 錯誤。本文提供完整的函數建立範例(含游標迴圈拼接字串),並詳細解析三種解決方案的優劣與適用場景。
SHOW VARIABLES LIKE 'log_bin_trust_function_creators';
-- Value = OFF 時需開啟
USE app02;
DELIMITER //
DROP FUNCTION IF EXISTS `testhanshu`;
CREATE FUNCTION `testhanshu`(`tustate` INT)
RETURNS VARCHAR(2000)
BEGIN
DECLARE oneAddr VARCHAR(200) DEFAULT '';
DECLARE allAddr VARCHAR(2000) DEFAULT '';
DECLARE done INT DEFAULT FALSE;
DECLARE curl CURSOR FOR
SELECT utruename FROM tsys_user WHERE ustate = tustate;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN curl;
REPEAT
FETCH curl INTO oneAddr;
IF NOT done THEN
SET oneAddr = CONCAT(oneAddr, ';');
SET allAddr = CONCAT(allAddr, oneAddr);
END IF;
UNTIL done END REPEAT;
CLOSE curl;
RETURN allAddr;
END;
//
DELIMITER ;
-- 測試呼叫
SELECT testhanshu(1);
錯誤訊息:
This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
根因:啟用 binlog 時,MySQL 要求函數聲明確定性特性,確保主從同步一致性。
SET GLOBAL log_bin_trust_function_creators = 1;
編輯啟動腳本或服務配置,加入參數:
--log-bin-trust-function-creators=1
my.cnf 設定(推薦生產)[mysqld]
log-bin-trust-function-creators=1
與其開啟信任開關,不如在函數定義中明確宣告特性:
CREATE FUNCTION `testhanshu`(`tustate` INT)
RETURNS VARCHAR(2000)
DETERMINISTIC -- 相同輸入必產生相同輸出
READS SQL DATA -- 僅讀取資料,不修改
BEGIN
-- 函數本體
END;
DETERMINISTIC:優化器可快取結果,主從同步安全READS SQL DATA:告知引擎僅讀操作NO SQL:完全不存取資料(純計算)MODIFIES SQL DATA:會修改資料(函數中禁止,僅程序可用)建議:優先加上 DETERMINISTIC READS SQL DATA,僅在確無法滿足(如呼叫 UUID()、RAND())時才考慮開啟信任開關。
GROUP_CONCAT:SELECT GROUP_CONCAT(utruename SEPARATOR ';')
FROM tsys_user WHERE ustate = 1;
JOIN、子查詢、視圖替代時盡量不用 UDF理解二進制日誌與函數確定性的關係,正確聲明特性而非盲目開啟信任開關,才是專業 DBA 的態度。