locked
Guardar procedimientos almacenados sin validaciones RRS feed

  • Pregunta

  • Saludos,

    Un servidor con SQL Server 2008 de 64bits. En un procedimiento almacenado tengo referencias a servidores vinculados. Estos existen en el entorno de producción, porque en el desarrollo no necesito en esta fase dichos servidores.

    El caso es que al tratar de modificar el procedimiento almacenado en desarrollo y no disponer de dichos servidores vinculados, salta el error

    Mens 7202, Nivel 11, Estado 2, Procedimiento spMIPROCEDIMIENTO, Línea 37
    No se encuentra el servidor 'MI_SERVIDOR_VINCULADO' en sys.servers. Compruebe que se haya especificado el nombre de servidor correcto. Si es necesario, ejecute el procedimiento almacenado sp_addlinkedserver para agregar el servidor a sys.servers.

    Quiero tener actualizado este procedimiento en mi base de datos de desarrollo, pero no consigo guardarlo con las modificaciones; la única forma que encuentro es restaurar en desarrollo la base de datos de producción una vez realizados los cambios. ¿Conocéis alguna forma de "saltar" estas validaciones y que pueda almacenar el procedimiento almacenado aunque diera fallos de este tipo?

    Gracias de antemano.

    jueves, 28 de agosto de 2014 8:49

Respuestas

  • Hola.

    Para empezar, viendo el procedimiento que nos facilitas, yo diría que el problema se debe a bloqueos a la hora de truncar, y no al traer datos. En esa línea, implementaría controles de timeout y disponibilidad del servidor vinculado antes de acceder para traerte los datos.

    En general, yo emplearía OpenQuery en lugar de el acceso al nombre con cuatro partes. Es recurrir al servidor vinculado igual, pero la diferencia rendimiento es importante, sobre todo en casos en los que haya que hacer filtros de la información. Pruébalo, verás que hay una enorme diferencia.

    En casos de gran número de registros, trataría de implementar una actualización incremental y no truncar y cargar. Investiga si las tablas en origen cuentan con campos de auditoría (fechas de alta o modificación) que permitan recuperar únicamente los registros modificados en los últimos días, y no todos. Luego, tratas esos únicamente. Si son tablas maestras, además serán muy escasos los cambios que se produzcan. Es más laborioso, pero muchísimo más ligero. También evitas problemas de bloqueos en gran medida, ya que no has de bloquear la tabla completa. También impides que haya tablas vacías en ningún momento.

    Para tablas que haya que volcar completas y sean de cierto tamaño, yo no lo haría tampoco truncando y cargando, sino preparando una tabla nueva (con la misma estructura, claves e índices incluidos), pero con otro nombre. Le refrescas los datos y por último renombras las tablas. En cuanto a IO, es muy similar al ejemplo que has pasado, pero la diferencia está en que en ningún momento la tabla está vacía, ya que el renombrado es casi instantáneo.

    Espero que estas sugerencias te permitan implementar más eficazmente el proceso de actualización de esa información. Si te surgen dudas, nos dices.



    Alberto López Grande
    SQL Server MVP
    Visita mi blog en http://qwalgrande.com
    Sígueme en twitter en http://twitter.com/qwalgrande

    • Propuesto como respuesta Uriel Almendra lunes, 1 de septiembre de 2014 14:41
    • Marcado como respuesta Uriel Almendra lunes, 1 de septiembre de 2014 14:41
    sábado, 30 de agosto de 2014 7:42
    Moderador

Todas las respuestas

  • Hola.

    Hasta donde yo sé, no es posible realizar tal cosa. Pero puedes agregar los servidores vinculados, y que apunten a un servidor que no sea el de producción, con el nombre que decidas darle (incluso jugando con alias).


    Alberto López Grande
    SQL Server MVP
    Visita mi blog en http://qwalgrande.com
    Sígueme en twitter en http://twitter.com/qwalgrande

    • Propuesto como respuesta Uriel Almendra jueves, 28 de agosto de 2014 21:19
    jueves, 28 de agosto de 2014 10:26
    Moderador
  • Hola Alberto,

    Es la opción que me queda si no se puede hacer lo que pregunto. Lo malo es que no vale con crear el servidor, sino que tengo que generar también la estructura de tablas que se referencian, y quería evitarlo si era posible.

    Gracias y un saludo,

    jueves, 28 de agosto de 2014 10:35
  • Si se puede, pero tendrías que utilizar Queries dinámicos

    te dejo un ejemplo

    DECLARE @SQLString AS NVARCHAR(4000), @address AS NVARCHAR(60);
    
    SET @SQLString = N'
    
    SELECT custid, companyname, contactname, contacttitle, address
    
    FROM [Sales].[Customers]
    
    WHERE address = @address';
    
     
    
    SET @address = N'5678 rue de l''Abbaye';
    
     
    
    EXEC sp_executesql  @statement = @SQLString
    
                       ,@params = N'@address NVARCHAR(60)'
    
                       ,@address = @address;
    
     
    

    otro ejemplo.

    DECLARE @SQLString AS NVARCHAR(4000)
    
    , @outercount AS int;
    
    
    SET @SQLString = N'SET @innercount = (SELECT COUNT(*) FROM Production.Products)';
    
    
    
    EXEC sp_executesql
    
    @statment = @SQLString
    
    , @params = N'@innercount AS int OUTPUT'
    
    , @innercount = @outercount OUTPUT;
    
    
    SELECT @outercount AS 'RowCount';
    


    saludos

    jueves, 28 de agosto de 2014 17:51
  • Gracias kakaroto2012,  tomo nota.

    Le veo un inconveniente porque no os he contado todo mi proceso: dentro del procedimiento una de las operaciones con el servidor vinculado introduce el resultado en una tabla temporal. Si dejo solo esa parte en un EXEC, una vez finalizado éste la tabla temporal se elimina, por lo que me veo obligado a introducir todo el código del procedimiento almacenado dentro del EXEC.

    Una curiosidad, ¿esto puede ser menos eficiente en ejecución? Lo digo de cara a que no queden planes de ejecución específicos para cada una de las consultas que haya dentro del EXEC. Tampoco le doy más importancia a este punto en este caso concreto, pues manejo un volumen pequeño de datos en el procedimiento y las operaciones son sencillas.

    Un saludo,

    viernes, 29 de agosto de 2014 10:47
  • Hola.

    Con el debido respeto, desmarco la contestación de kakaroto2012 como respuesta, ya que no responde a la cuestión planteada y no es una buena práctica, sino todo lo contrario. Nunca se debe perjudicar el rendimiento ni la calidad en producción por el mantenimiento del entorno de desarrollo. Visto por otro usuario, se podría malinterpretar y entenderse como de aplicación general, cuando, de serlo, sería únicamente para escenarios muy particulares.

    Los problemas que apunta el OP son dos de los que se producirían, sin contar el aumento en el coste de los desarrollos, y sobre todo, de las pruebas de los mismos y el aumento en la complejidad de la gestión de la seguridad. El rendimiento, si se hiciera muy bien, sería en la práctica casi equivalente. Lo que no podría hacerse es probarse, ya que seguirá sin funcionar.

    La respuesta adecuada al problema que se plantea consiste en contar con un entorno de desarrollo que sea completo, y eso incluye la recreación de todos los servidores vinculados, que han de existir como servidores de desarrollo también. Entendiendo que eso no siempre es posible, existen alternativas que pueden paliar el problema, si se tiene como premisa que el procedimiento de desarrollo y el de producción sean idénticos. Para ello existen herramientas de gestión de código fuente, pueden parametrizarse los despliegues, etc.

    Hay que tener en cuenta que el uso de servidores vinculados ha de ser algo excepcional, no general, ya que el rendimiento que prestan dista mucho de ser eficiente, sobre todo comparado con el acceso directo a la otra fuente. Habría que conocer con cierto detalle qué se precisa de esos accesos a servidor vinculado para poder facilitar alternativas a la de contar con todo el entorno de producción reproducido como entorno de desarrollo.


    Alberto López Grande
    SQL Server MVP
    Visita mi blog en http://qwalgrande.com
    Sígueme en twitter en http://twitter.com/qwalgrande

    viernes, 29 de agosto de 2014 12:00
    Moderador
  • Básicamente los empleo para hacer una carga de datos maestros que residen en un servidor Oracle. Inicialmente la comunicación con el mismo la realizábamos con un EXEC, por muy malo que esto pueda ser.

    Por una incidencia con dicho servidor, en que el procedimiento almacenado en ocasiones se queda en estado ejecución indefinidamente, y la única forma de "matarlo" es reiniciar SQL Server, desde Microsoft se nos ha recomendado como parte de la solución para aislar este comportamiento, introducir los datos del maestro (el servidor Oracle) en una tabla temporal con la que realizar las operaciones.

    Gracias y un saludo.

    viernes, 29 de agosto de 2014 12:15
  • Hola.

    Existen muchas formas de volcar datos desde Oracle a SQL Server. ¿Puedes compartir cómo lo realizas ahora mismo (un ejemplo)?

    Recuerda que puedes replicar los datos, volcarlos periódicamente con un job o leerlos filtrados al vuelo con un rendimiento bastante bueno, pero habría que saber cómo lo haces para determinar si es mejorable.


    Alberto López Grande
    SQL Server MVP
    Visita mi blog en http://qwalgrande.com
    Sígueme en twitter en http://twitter.com/qwalgrande

    viernes, 29 de agosto de 2014 12:27
    Moderador
  • A día de hoy disponemos de varios procedimientos almacenados que periódicamente son invocados desde un trabajo SQL.

    El caso más sencillo sería una importación de tabla completa:

     

    CREATE PROCEDURE [dbo].[spSAPKMFProcesarHSECCIONES] AS DECLARE @ErrMsg nvarchar(4000), @ErrSeverity int, BEGIN BEGIN TRY --Importación temporal de los datos desde ORACLE --Tabla temporal para emplear en la transacción SELECT * INTO [#SECCIONES] FROM ServidorVinculado..OrigenSecciones --Vaciado y llenado de la tabla herMES de Secciones BEGIN TRANSACTION TRUNCATE TABLE Secciones INSERT INTO Secciones (C1, C2, C3) SELECT C1, C2, C3 FROM [#SECCIONES] COMMIT TRANSACTION RETURN 0 END TRY BEGIN CATCH --ESCRITURA EN UNA TABLA DE LOG --... IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION -- Raise an error with the details of the exception SELECT @ErrMsg = ERROR_MESSAGE(), @ErrSeverity = ERROR_SEVERITY() RAISERROR(@ErrMsg, @ErrSeverity, 1) RETURN 1 END CATCH END

    Gracias.

    viernes, 29 de agosto de 2014 12:38
  • Hola.

    Si encima me dices que lo ejecutas desde un job, ¿por qué no empleas SSIS para esta operación? Es mucho más eficiente y controlable que de la forma en que lo realizas.

    Y si lo has de hacer con procedimientos almacenados, hay otras formas más eficaces. Que tengas que pasar tablas así, y encima con una temporal de por medio, deja mucho que desear en cuanto al rendimiento.


    Alberto López Grande
    SQL Server MVP
    Visita mi blog en http://qwalgrande.com
    Sígueme en twitter en http://twitter.com/qwalgrande

    viernes, 29 de agosto de 2014 12:49
    Moderador
  • El tema es que la aplicación es "vieja", lleva unos cuantos años en producción y cambiar todos los procedimientos a SSIS está complicado que el cliente aborde las modificaciones.

    Y ya me has picado la curiosidad, porque con procedimientos almacenados no tengo idea de cómo hacerlo que no sea con servidores vinculados. Sería genial si puedes aportar alguna breve orientación en este sentido. Muchas gracias!

    viernes, 29 de agosto de 2014 13:01
  • Hola.

    Para empezar, viendo el procedimiento que nos facilitas, yo diría que el problema se debe a bloqueos a la hora de truncar, y no al traer datos. En esa línea, implementaría controles de timeout y disponibilidad del servidor vinculado antes de acceder para traerte los datos.

    En general, yo emplearía OpenQuery en lugar de el acceso al nombre con cuatro partes. Es recurrir al servidor vinculado igual, pero la diferencia rendimiento es importante, sobre todo en casos en los que haya que hacer filtros de la información. Pruébalo, verás que hay una enorme diferencia.

    En casos de gran número de registros, trataría de implementar una actualización incremental y no truncar y cargar. Investiga si las tablas en origen cuentan con campos de auditoría (fechas de alta o modificación) que permitan recuperar únicamente los registros modificados en los últimos días, y no todos. Luego, tratas esos únicamente. Si son tablas maestras, además serán muy escasos los cambios que se produzcan. Es más laborioso, pero muchísimo más ligero. También evitas problemas de bloqueos en gran medida, ya que no has de bloquear la tabla completa. También impides que haya tablas vacías en ningún momento.

    Para tablas que haya que volcar completas y sean de cierto tamaño, yo no lo haría tampoco truncando y cargando, sino preparando una tabla nueva (con la misma estructura, claves e índices incluidos), pero con otro nombre. Le refrescas los datos y por último renombras las tablas. En cuanto a IO, es muy similar al ejemplo que has pasado, pero la diferencia está en que en ningún momento la tabla está vacía, ya que el renombrado es casi instantáneo.

    Espero que estas sugerencias te permitan implementar más eficazmente el proceso de actualización de esa información. Si te surgen dudas, nos dices.



    Alberto López Grande
    SQL Server MVP
    Visita mi blog en http://qwalgrande.com
    Sígueme en twitter en http://twitter.com/qwalgrande

    • Propuesto como respuesta Uriel Almendra lunes, 1 de septiembre de 2014 14:41
    • Marcado como respuesta Uriel Almendra lunes, 1 de septiembre de 2014 14:41
    sábado, 30 de agosto de 2014 7:42
    Moderador
  • Gracias Alberto, tomo buena nota de todas tus sugerencias para esta y futuras ocasiones.

    En cuanto a la incidencia que se nos da, ya os contaré cuando quede resuelta.

    Un saludo,

    lunes, 1 de septiembre de 2014 7:57