2011-02-07 18 views
14

Nuestra base de datos tiene una función para generar un número de orden. Lee un valor de una tabla de Configuraciones, lo incrementa y luego devuelve el nuevo valor. Por ejemplo:CREAR error de FUNCIÓN "Esta función no tiene DETERMINISTIC, NO SQL o READS SQL DATA"

CREATE FUNCTION NextOrderNumber() RETURNS INTEGER UNSIGNED NOT DETERMINISTIC 
BEGIN 
    DECLARE number INTEGER UNSIGNED; 
    UPDATE Settings SET IntegerValue=LAST_INSERT_ID(IntegerValue+1) WHERE KeyName='NextOrderNumber'; 
    SET number=LAST_INSERT_ID(); 
    return number; 
END 

Nota: No critique esta función Sé que tiene defectos, es sólo para ilustración.

podemos usar esta función como sigue:

INSERT INTO Orders(OrderNumber, ...) 
SELECT NextOrderNumber(), ... 

Cuando está habilitado el registro binario, CREATE FUNCTION da este error:

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)

Independientemente de lo binlog_format está establecido, es en realidad un problema con la función anterior? De acuerdo con mi lectura del relevante MySQL page, no puedo ver ninguna razón por la cual esta función sea incompatible con la replicación, con ROW o STATEMENT nivel de registro binario.

Si la función es segura, establecer el log_bin_trust_function_creators = 1 global me inquieta. No quiero deshabilitar esta comprobación para todas las funciones, solo esta. ¿Podría simplemente marcar la función como NO SQL para suprimir la advertencia? Lo intenté y funcionó. ¿Esto causará algún problema?

Respuesta

0

Piense en lo que se escribe en el registro binario.

No se puede garantizar que una orden creada en un maestro tenga la misma secuencia generada para ella cuando la transacción se ejecuta en un esclavo o, lo que es más probable, por otro maestro en el clúster. p.ej.

0) Node 1 and Node 2 are in sync, NextOrderNumber=100 
1) Node 1 receives insert statement wrt order from customer A and assigns 
    order number 100, changes its NextOrderNumber to 101 
2) Node 1 writes the settings update to the log 
3) Node 1 writes the insert statement to the log 
4) Node 2 processes for customer B, asigns order number 100 and increments 
5) Node 2 writes the settings update from to the log 
6) Node 2 writes the insert statement to the log 
7) Nodes 2 reads settings update from the log @2 
     - Its NextOrderNumber is now 102 
8) Node 2 reads insert from log @3, tries to apply it but it fails 
     due to duplicate key 
9) Node 1 reads the update @5 - Its nextOrderNumber is also now 102 
10) Node1 reads insert from log @6 - 
     but this fails due to duplicate key 

Ahora pedidos 100 en los nodos 2 se refieren a diferentes datos, y no hay un orden 101.

Hay una razón que ha habido una gran cantidad de funcionalidad añadida a modificar el comportamiento de las variables AUTO_INCREMENT .

Si ajusta la inserción en un procedimiento, que recupera un valor del generador de secuencias y luego lo inserta en la instrucción de inserción, se resolverá el problema inmediato; sin embargo, debe pensar cómo evitar asignar el mismo número dos veces usando diferentes nodos de base de datos.

+0

symcbean - Entiendo que este enfoque no funciona en un clúster. No estoy preguntando sobre ese escenario. Pregunto acerca de la configuración simple maestro-esclavo donde las inserciones/actualizaciones solo tienen lugar en un solo lugar. – richb

24

He buscado en Google y aquí estoy. he encontrado una manera:

SET GLOBAL log_bin_trust_function_creators = 1; 

Pero tenga cuidado, puede ser peligroso para la recuperación de datos o la replicación ...

+8

Esto no aborda la pregunta de ninguna manera. – richb

+0

@richb pero funciona. –

5

Según mi subestimar que causa un problema cuando la recuperación de datos o la replicación

Ref: http://dev.mysql.com/doc/refman/5.0/en/stored-programs-logging.html

MySQL 5.0.6: Se registran las declaraciones que crean rutinas almacenadas y las declaraciones CALL. Las invocaciones de funciones almacenadas se registran cuando se producen en sentencias que actualizan datos (porque esas declaraciones se registran).

Sin embargo, las invocaciones de función no se registran cuando se producen en sentencias como SELECT que no cambian datos, incluso si se produce un cambio de datos dentro de una función; esto puede causar problemas.

En algunas circunstancias, las funciones y procedimientos pueden tener diferentes efectos si se ejecutan en diferentes momentos o en diferentes máquinas (maestra y esclava) y, por lo tanto, pueden ser inseguras para la recuperación o replicación de datos.

E.g.

CREATE FUNCTION myfunc() RETURNS INT DETERMINISTIC 
BEGIN 
    INSERT INTO t (i) VALUES(1); 
    RETURN 0; 
END; 

SELECT myfunc(); 

Si una función almacenada se invoca dentro de una instrucción SELECT como que no modifica los datos, la ejecución de la función no se escribe en el registro binario, incluso si la propia función modifica los datos. Este comportamiento de registro tiene el potencial de causar problemas. Supongamos que una función myfunc() se define como anteriormente.

+0

No creo que esto sea correcto. Si mira [link] (https://dev.mysql.com/doc/refman/5.7/en/stored-programs-logging.html), verá _italics _... Para las funciones almacenadas, los cambios de fila realizados dentro de la función son registrado, no la invocación de la función. Para desencadenantes, se registran los cambios de fila realizados por el desencadenador. ... _italics_. Entonces, para mí es inexplicable por qué logbin_format = ROW todavía parece no permitir funciones que no están marcadas como DETERMINISTIC. –

-3

ejecutar esta justo antes de la creación de la función:

SET @@global.log_bin_trust_function_creators = 1; 

y añadir MODIFIES SQL DATA a la declaración.

Además ... bueno, pidió no comentar la función en sí, pero le sugiero que suelte la variable number y simplemente haga RETURN LAST_INSERT_ID().

+1

Esto no funciona. log_bin_trust_function_creators es GLOBAL, no una variable de sesión. – richb

+0

Lo siento, fue un error tipográfico. Edité mi respuesta. –

+0

¿Eh? El comportamiento global no se ve afectado? Sí lo es. Estás configurando una variable global. – richb

1

Hay dos maneras de solucionar este problema:

ejecute el siguiente en la consola de MySQL:

SET GLOBAL log_bin_trust_function_creators = 1; 

Añadir lo siguiente al archivo de configuración mysql.ini:

log_bin_trust_function_creators = 1 

El configuración relaja la comprobación de funciones no deterministas. Las funciones no deterministas son funciones que modifican datos (es decir, tienen declaración (es), inserción (es) o eliminación (es) de declaración (es)). Para más información, mira aquí.

Tenga en cuenta que si el registro binario NO está habilitado, esta configuración no se aplica.

+0

me enfrento a este error cuando selecciono la tabla de la vista. ¿Cual puede ser la solución? – sat

0

Could I instead just flag the function as NO SQL to suppress the warning? I tried it and it worked. Will this cause any problem?

De acuerdo con esta Mysql doc:

Assessment of the nature of a function is based on the “honesty” of the creator: MySQL does not check that a function declared DETERMINISTIC is free of statements that produce nondeterministic results.

Por lo tanto, depende de usted. Si está seguro de que el método no causará ningún problema ...

Cuestiones relacionadas