Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Mysql »

Debería usar un Stored Procedure?

Estas en el tema de Debería usar un Stored Procedure? en el foro de Mysql en Foros del Web. Buenas, Me gustaría saber vuestra opinión al respecto. Resulta que en cada registro nuevo de usuario en mi aplicación web, debo realizar 3 inserts a ...
  #1 (permalink)  
Antiguo 04/10/2010, 00:08
Avatar de neodani  
Fecha de Ingreso: marzo-2007
Mensajes: 1.811
Antigüedad: 17 años, 8 meses
Puntos: 20
Debería usar un Stored Procedure?

Buenas,

Me gustaría saber vuestra opinión al respecto. Resulta que en cada registro nuevo de usuario en mi aplicación web, debo realizar 3 inserts a 3 tablas diferentes.

¿Me convendría usar un Stored Procedure? Nunca llegué a usar uno y no sé si en este caso sería buena idea o no.

Muchas gracias de antemano
  #2 (permalink)  
Antiguo 04/10/2010, 03:43
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 17 años
Puntos: 2658
Respuesta: Debería usar un Stored Procedure?

Cita:
Iniciado por neodani Ver Mensaje
Buenas,

Me gustaría saber vuestra opinión al respecto. Resulta que en cada registro nuevo de usuario en mi aplicación web, debo realizar 3 inserts a 3 tablas diferentes.

¿Me convendría usar un Stored Procedure? Nunca llegué a usar uno y no sé si en este caso sería buena idea o no.

Muchas gracias de antemano
La respuesta básica es si, te convendría si los parámetros de los inserts no son compartidos.
Pero si las otras dos tablas toman datos que ya están en la primera o son producidos por ella (por ejemplo, el ID si es numérico) es posible que con un TRIGGER sea suficiente.

¿Cuál es el caso? Danos un poquito de detalles respeto de los parámetros y cómo se reparten.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #3 (permalink)  
Antiguo 04/10/2010, 12:25
Avatar de neodani  
Fecha de Ingreso: marzo-2007
Mensajes: 1.811
Antigüedad: 17 años, 8 meses
Puntos: 20
Respuesta: Debería usar un Stored Procedure?

Cita:
Iniciado por gnzsoloyo Ver Mensaje
La respuesta básica es si, te convendría si los parámetros de los inserts no son compartidos.
Pero si las otras dos tablas toman datos que ya están en la primera o son producidos por ella (por ejemplo, el ID si es numérico) es posible que con un TRIGGER sea suficiente.

¿Cuál es el caso? Danos un poquito de detalles respeto de los parámetros y cómo se reparten.
Buenas gnzsoloyo,

La función que inserta en las tres tablas es la siguiente:

Código PHP:
Ver original
  1. public function addNewUser($nombre,$usuario,$password,$correo,$pais,$birthday,$sexo,$userReferido){
  2.        
  3.         $this->_nombre=$nombre;
  4.         $this->_usuario=$usuario;
  5.         $this->_password=$password;
  6.         $this->_correo=$correo;
  7.         $this->_pais=$pais;
  8.         $this->_birthday=$birthday;
  9.         $this->_sexo=$sexo;
  10.         $this->_userReferido=$userReferido;
  11.         $this->_userKey = $this->randomKeygen($length=10);
  12.         $ip=getRealIP();
  13.         $this->_userId=1; /*hardcore */
  14.        
  15.         // Inserta datos en la TBL_USERS
  16.         $query = "INSERT INTO tbl_user (user_login,user_pass,user_activation_key) VALUES (:user_login,:user_pass,:user_activation_key)";
  17.  
  18.         $comando = $this->_con->prepare($query);
  19.         $comando->execute(array(':user_login'=>$this->_usuario,
  20.                                 ':user_pass'=>$this->_password,
  21.                                 ':user_activation_key'=>$this->_userKey));
  22.        
  23.         // Inserta datos en la TBL_USERS_PERSONAL
  24.         $query = "INSERT INTO tbl_user_personal (user_id,user_name,user_mail,user_birthday,user_sexo,user_pais) VALUES (:user_id,:user_name,:user_mail,:user_birthday,:user_sexo,:user_pais)";
  25.         $comando = $this->_con->prepare($query);
  26.         $comando->execute(array(':user_id'=>$this->_userId,
  27.                                 ':user_name'=>$this->_nombre,
  28.                                 ':user_mail'=>$this->_correo,
  29.                                 ':user_birthday'=>$this->_birthday,
  30.                                 ':user_sexo'=>$this->_sexo,
  31.                                 ':user_pais'=>$this->_pais));
  32.        
  33.         // Inserta datos en la TBL_REGISTRO
  34.         $query = "INSERT INTO tbl_registro (user_id,fecha_registro,ip_registro) VALUES (:user_id,now(),:ip)";
  35.         $comando = $this->_con->prepare($query);
  36.        
  37.         $comando->execute(array(':user_id'=>$this->_userId,
  38.                                 ':ip'=>$ip));
  39.        
  40.     }

Primero inserto en la TBL_USERS la cual tiene un campo user_id es autoincremental y PK.
El problema está en las dos siguientes inserciones que dependen del valor del user_id insertado en la TBL_USERS para luego en las otras dos tablas poder ingresarlo (de ahí la relación de FK).
En el ejemplo lo he puesto "hardcore" este valor (linea 13).

Te pego el diseño de las tablas para que lo veas mas claro.
Aprovecho para preguntarte si las dos claves foráneas de las tablas USER_PERSONAL y REGISTRO, deberían ser también primarias?...



Muchas gracias de antemano!
  #4 (permalink)  
Antiguo 05/10/2010, 07:10
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 17 años
Puntos: 2658
Respuesta: Debería usar un Stored Procedure?

Bueno, en ese contexto, lo que más te conviene es usar un stored procedure, ya que los datos a ingresar en las tres tablas son diferentes. No hay modo de administrar eso por un TRIGGER, ya que un TRIGGER sólo puede recibir como parámetros los datos de su propia tabla.
El único inconveniente para la codificación de un SP así es la cantidad de datos a ingresar, pero eso no es un limtante.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #5 (permalink)  
Antiguo 05/10/2010, 14:04
Avatar de neodani  
Fecha de Ingreso: marzo-2007
Mensajes: 1.811
Antigüedad: 17 años, 8 meses
Puntos: 20
Respuesta: Debería usar un Stored Procedure?

Cita:
Iniciado por gnzsoloyo Ver Mensaje
Bueno, en ese contexto, lo que más te conviene es usar un stored procedure, ya que los datos a ingresar en las tres tablas son diferentes. No hay modo de administrar eso por un TRIGGER, ya que un TRIGGER sólo puede recibir como parámetros los datos de su propia tabla.
El único inconveniente para la codificación de un SP así es la cantidad de datos a ingresar, pero eso no es un limtante.
Gracias gnzsoloyo,

El SP, sería así?

Código SQL:
Ver original
  1. CREATE PROCEDURE nuevoUsuario (
  2. @user_id INT,
  3. @user_login VARCHAR(25),
  4. @user_pass VARCHAR(30),
  5. @user_activation_key VARCHAR(40),
  6. @user_name VARCHAR(30),
  7. @user_mail VARCHAR(45),
  8. @user_birthday DATE,
  9. @user_sexo CHAR(1),
  10. @user_pais SMALLINT,
  11. @fecha_registro TIMESTAMP,
  12. @ip_registro VARCHAR(15)
  13. )
  14.  
  15. BEGIN
  16. INSERT INTO tbl_user (user_login,user_pass,user_activation_key) VALUES (@user_login,@user_pass,@user_activation_key);
  17.  
  18. INSERT INTO tbl_user_personal (user_id,user_name,user_mail,user_birthday,user_sexo,user_pais) VALUES (@user_id,@user_name,@user_mail,@user_birthday,@user_sexo,@user_pais);
  19.  
  20. INSERT INTO tbl_registro (user_id,fecha_registro,ip_registro) VALUES (@user_id,now(),@ip);
  21. END

El problema que tengo es como sé el user_id de los dos últimos inserts. Ya que al hacer el primer insert, se crea una nueva fila en la tbl_user, la cual tiene una PK que es el user_id. Pues como diablos hago para que los dos inserts siguientes usen el user_id que se acaba de crear en la tbl_user?


¿Alguien sabe y puede ayudarme?

Muchas gracias de antemano
  #6 (permalink)  
Antiguo 05/10/2010, 14:22
Avatar de Nano_  
Fecha de Ingreso: febrero-2006
Ubicación: Bogotá, Colombia
Mensajes: 1.866
Antigüedad: 18 años, 9 meses
Puntos: 96
Respuesta: Debería usar un Stored Procedure?

Saludos

Se me ocurre algo asi:

Código MySQL:
Ver original
  1.  
  2. INSERT INTO tbl_user (user_login,user_pass,user_activation_key) VALUES (@user_login,@user_pass,@user_activation_key);
  3.  
  4.  
  5.  
  6. INSERT INTO tbl_user_personal (user_id,user_name,user_mail,user_birthday,user_sexo,user_pais) VALUES ((SELECT LAST_INSERT_ID()),@user_name,@user_mail,@user_birthday,@user_sexo,@user_pais);
  7.  
  8.  
  9.  
  10. INSERT INTO tbl_registro (user_id,fecha_registro,ip_registro) VALUES ((SELECT LAST_INSERT_ID()),now(),@ip);
  11.  

Prueba y cualquier novedad lo comentas.

Hasta Pronto
__________________
:.:Nano.:: @nano_hard - Retornando al foro
  #7 (permalink)  
Antiguo 05/10/2010, 16:05
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 17 años
Puntos: 2658
Respuesta: Debería usar un Stored Procedure?

Vamos a algunos detalles:

1) Cuando haces una inserción de este tipo, en el que se ven afectadas más de una tabla, es conveniente usar transacciones, de modo que si algo falla, se deshagan todas las inserciones (cuestiones de consistencia).

2) Las variables de entrada no se usan con "@". Eso es de SQL Server (Microsoft) y no de MySQL. Las variables se usan simplemente declarandolas en el prototipo y usandolas con su nombre.

3) Las variables con "@" son variables de usuario y siguen existiendo y con su valor mientras dure la conexión. No es conveniente usarlas si no es estrictamente necesario precisamente por su permanencia, y cada vez que se las invoca deben ser inicializadas para evitar que guarden basura. Son muy útiles en cierto tipo de operaciones, pero no es buena prática usarlas en el prototipo de los SP, entre otras cosas porque si por alguna razón dos SP distintos que usan la misma variable son invocados por el mismo usuario en la misma sesión (threads de ejecución diferentes), el cambio de valor de la variable en un thread afectará el valor de la variable en el otro thread, simplemente porque apuntan a lo mismo...

4) Las variables no deben bajo ninguna circunstancia tener el mismo nombre de campos, tablas, bases o cualquier otro objeto de base de datos, porque el parser confundirá los objetos, ya que jerarquiza los mismos y en ese caso una tabla o un campo tienen mayor jerarquía que una variable, en consecuencia intentará acceder al campo o tabla y no a la variable, lo que puede dar lugar a errores aleatorios.

Este sería un modelo, basado en tu ejemplo:
Código MySQL:
Ver original
  1. CREATE PROCEDURE nuevoUsuario (
  2.   IN vuser_id int,
  3.   IN vuser_login varchar(25),
  4.   IN vuser_pass varchar(30),
  5.   IN vuser_activation_key varchar(40),
  6.   IN vuser_name varchar(30),
  7.   IN vuser_mail varchar(45),
  8.   IN vuser_birthday date,
  9.   IN vuser_sexo char(1),
  10.   IN vuser_pais smallint,
  11.   IN vfecha_registro timestamp,
  12.   IN vip_registro varchar(15))
  13.  
  14.  
  15.  
  16.   INSERT INTO tbl_user(
  17.     user_login,
  18.     user_pass,
  19.     user_activation_key)
  20.   VALUES(
  21.     vuser_login,
  22.     vuser_pass,
  23.     vuser_activation_key);
  24.  
  25.   INSERT INTO tbl_user_personal(
  26.     vuser_id,
  27.     vuser_name,
  28.     vuser_mail,
  29.     vuser_birthday,
  30.     vuser_sexo,
  31.     vuser_pais)
  32.   VALUES (
  33.     vuser_id,
  34.     vuser_name,
  35.     vuser_mail,
  36.     vuser_birthday,
  37.     vuser_sexo,
  38.     vuser_pais);
  39.  
  40.   INSERT INTO tbl_registro (
  41.     vuser_id,
  42.     vfecha_registro,
  43.     vip_registro)
  44.   VALUES (
  45.     vuser_id,
  46.     NOW(),
  47.     vip_registro);
  48.  
  49.  

Es de buenas prácticas Poner el sentido de entrada/salida de las variables, por más que el IN sea implícito. Facilita cualquier análisis rápido y además de ese modo no te olvidas de poner los OUT o INOUT cuando corresponden.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)

Última edición por gnzsoloyo; 05/10/2010 a las 16:14
  #8 (permalink)  
Antiguo 05/10/2010, 23:41
Avatar de neodani  
Fecha de Ingreso: marzo-2007
Mensajes: 1.811
Antigüedad: 17 años, 8 meses
Puntos: 20
Respuesta: Debería usar un Stored Procedure?

Cita:
Iniciado por gnzsoloyo Ver Mensaje
Vamos a algunos detalles:

1) Cuando haces una inserción de este tipo, en el que se ven afectadas más de una tabla, es conveniente usar transacciones, de modo que si algo falla, se deshagan todas las inserciones (cuestiones de consistencia).
Muchas gracias por la explicación gnzsoloyo, fenomenal

Respecto al punto 1 que he citado.

1) Las transacciones solo se pueden hacer en SP, no? en triger o cualquier otra función no existen verdad?

2) Si hay algún insert que falla, (ej. el número dos) automáticamente se hace rollback de todo, o tengo que indicárselo en algún lado?

3) Existe alguna forma de confirmar que el procedimiento ha ido bien? generar algún tipo de respuesta TRUE o FALSE para que yo desde PHP pueda saber si se ejecutó correctamente?

Muchas gracias de antemano
  #9 (permalink)  
Antiguo 06/10/2010, 03:59
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 17 años
Puntos: 2658
Respuesta: Debería usar un Stored Procedure?

Cita:
1) Las transacciones solo se pueden hacer en SP, no? en triger o cualquier otra función no existen verdad?
En MySQL, al menos, un TRIGGER no puede llamar a una transaccion.
Sí puedes iniciar una transacción por fuera del SP (a nivel programático) y cerrar el commint una vez que el resultado ha sido el esperado.
Lo que viene bien para esto último es hacer un control de flujo de ejecuciones por medio del ROW_COUNT(), por ejemplo, que devuelve la cantidad de registros afectados por la sentencia.

Cita:
2) Si hay algún insert que falla, (ej. el número dos) automáticamente se hace rollback de todo, o tengo que indicárselo en algún lado?
Si cierras las conexión sin COMMIT, el ROLLBACK es implícito. normalmente lo mismo ocurre si el SP se corta o sale sin el COMMIT correspondiente.

Cita:
3) Existe alguna forma de confirmar que el procedimiento ha ido bien? generar algún tipo de respuesta TRUE o FALSE para que yo desde PHP pueda saber si se ejecutó correctamente?
Eso es medio obvio: SI una ejecución de sentencia (un SP es invocado como sentencia) se ejecuta bien, el valor del result de esa llamada es siempre TRUE... Pero eso lo peudes ver en el manual de PHP.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)

Etiquetas: procedure, stored
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 14:33.