2009-03-03 18 views
18

Quiero cambiar a las tablas de la mejor manera posible.
Tengo una tabla IpToCountry, y creo una nueva cada semana según un archivo CSV externo que importo.Intercambio de tablas ms-sql

La forma más rápida que he encontrado para hacer el cambio estaba haciendo lo siguiente:

sp_rename IpToCountry IpToCountryOld 
go 
sp_rename IpToCountryNew IpToCountry 
go 

El problema con esto es que la mesa puede ser accedido todavía en el medio.
¿Cómo abordo este problema en SQL?
Considerado el uso de sp_getapplock y sp_releaseapplock, pero quiero que la lectura de la tabla funcione lo más rápido posible.

+1

Estoy usando SQL server 2000. IpToCountryOld es irrelevante y podría haberse truncado y eliminado. Estoy cambiando el nombre porque es más rápido, luego elimino la tabla anterior ... –

Respuesta

16

Suponiendo que no puede actualizar/insertar en la tabla existente, ¿por qué no ajusta todo el acceso a la tabla con un view?

Por ejemplo, en un inicio se puede almacenar los datos en una tabla llamada IpToCountry20090303, y su punto de vista sería algo como esto:

CREATE VIEW IpToCountry 
AS 
SELECT * FROM IpToCountry20090303 

Cuando los nuevos datos entra, usted puede crear y rellenar el IpToCountry20090310 mesa. Una vez que la tabla se llena simplemente actualizar su punto de vista:

ALTER VIEW IpToCountry 
AS 
SELECT * FROM IpToCountry20090310 

El interruptor será completamente atómica, sin requerir ningún bloqueo o transacciones explícita. Una vez que la vista se haya actualizado, simplemente puede soltar la tabla anterior (o guardarla si lo prefiere).

+0

¿Es realmente así de simple? http://stackoverflow.com/questions/3716546/why-cant-sql-server-alter-a-view-in-a-stored-procedure – mg1075

0

¿Qué le sucede a IpToCountryOld? ¿Lo tiras? En ese caso, ¿por qué no truncar IpToCountry e importar mis nuevos datos?

Si necesita conservar los datos, ¿qué le parece guardar la fecha de carga en la tabla y almacenar la fecha de carga "actual" en algún lugar para ser utilizada en una cláusula WHERE? Luego cambia la fecha actual cuando los datos se cargan con éxito.

No dice qué DB está usando, así que no sé cuánto uso tiene, pero ¿tiene algún procedimiento almacenado que haga referencia a la tabla? Tenga en cuenta que en algunas plataformas los SP se compilan utilizando referencias internas a tablas que no cambiarán con un cambio de nombre, por lo que existe el riesgo de que los SP no recojan sus datos nuevos sin una recompilación. Lo mismo puede ser cierto para vistas y consultas analizadas almacenadas.

+0

Hola Mike, Estoy usando SQL Server 2000. Básicamente, la tabla anterior es irrelevante. la importación de datos tarda varios segundos (en una nueva tabla + indexación). Quiero reemplazar los datos con el daño mínimo del sistema ... –

0

¿No puedes importar a la única mesa fuera de horario?

O ¿por qué no simplemente hacer una actualización de datos, es decir, actualizar los registros existentes y agregar nuevos en un registro por registro a medida que realiza un ciclo para importar los datos. Esto permitiría que la tabla permanezca activa y reduzca el impacto general de agregar y eliminar tablas completas.

¿Cuál es la estructura de los datos que se importan, el diseño de la tabla, el formato, PK, etc.? De eso podemos darle una mejor respuesta.

+0

Los datos son direcciones IP (desde Ip, hasta Ip (juntos son PK), país, región, ciudad). Como los rangos de IP siempre cambian, actualizar con eliminar e insertar será un infierno. Puedo hacerlo fuera de horas, pero el reemplazo todavía causará tiempo de inactividad. Estoy tratando de descubrir la manera recomendada de ir ... –

1

Otro método para poner en práctica lo que está buscando para lograr sería el uso de la partición de tablas, una técnica que está disponible en la edición Enterprise de SQL Server.

El nombre de la tabla puede seguir siendo el mismo.Una vez completada la importación de la tabla, simplemente cambie la partición que contiene sus datos anteriores y cambie la nueva partición.

El siguiente Libro Blanco contiene toda la información que necesita para comenzar.

http://msdn.microsoft.com/en-us/library/ms345146.aspx

problemas Cheers, John

+0

Hola John, estas son algunas cosas interesantes. Aunque en SQL2000 aún me veré obligado a usar particiones de vistas, pero es bueno saberlo. Tengo algunas lecturas para hacer :) –

1

que he tenido que consiguen las funciones de partición para trabajar a gran escala. CREATE y DROP PARTITION son operaciones de bloqueo, y tienes poco control sobre el bloqueo, y si no puede obtener un bloqueo fallará con un nivel de gravedad 16 y matará tu conexión, que no puedes atrapar y volver a intentar sin restablecer la conexión. Pero podría funcionar bien para ti. Además, se requiere MSS Enterprise Edition, no se puede usar SE, podría ser demasiado para algunas tiendas más pequeñas o más costosas.

También encontré la vista redef para bloquear a gran escala (= volumen de transacciones + volumen puro de datos insertados constantemente, en mi caso) en tablas y objetos sys, por lo que esas operaciones pueden estancarse en cosas como reindexar y DTCCs - y en un caso, específicamente con un usuario en SSMS (de todas las cosas) tratando de explorar vistas en el Explorador de Objetos (alguien necesita decirles a esos tipos sobre READPAST). Nuevamente, su millaje puede variar.

En contraste, el sp_rename funciona bien para mí a escala: le da control sobre el bloqueo y el alcance del mismo. Para resolver el problema de bloqueo antes del intercambio, pruébelo como se muestra a continuación. A primera vista, esto parece tener el mismo problema de escala a gran volumen ... pero no lo he visto en la práctica. Entonces, funciona para mí ... pero una vez más, las necesidades y experiencias de todos son diferentes.

DECLARE @dummylock bit 
BEGIN TRANSACTION 
BEGIN TRY 
    -- necessary to obtain exclusive lock on the table prior to swapping 
    SELECT @dummylock = 1 WHERE EXISTS (SELECT 1 FROM A WITH (TABLOCKX)) 
    -- may or may not be necessary in your case 
    SELECT @dummylock = 1 WHERE EXISTS (SELECT 1 FROM B WITH (TABLOCKX)) 
    exec sp_rename 'A', 'TEMP' 
    exec sp_rename 'B', 'A' 
    exec sp_rename 'TEMP', 'B' 
    COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
    -- other error handling here if needed 
    ROLLBACK TRANSACTION 
END CATCH 
+0

Sin embargo, puedes hacer lo mismo con sp_getapplock y sp_releaseapplock, que OP no quiere – gbn

+0

@gbn, no creo que sp_getapplock funcione de la misma manera. sp_getapplock evitará dos ejecuciones simultáneas de un bloque de código, pero a menos que cada comando que * lea * esos datos también use el mismo bloqueo (probablemente en modo compartido), entonces no hay nada que impida que las lecturas se ejecuten cuando la primera tabla no lo haga existe. El nombre del recurso en sp_getapplock es solo una cadena arbitraria, y a menos que * todo * el acceso a esa tabla esté bloqueado por sp_getapplock, entonces cosas malas pueden suceder.Al usar TABLOCKX en la tabla en sí no puede haber lecturas, y no tiene que hacer nada más para evitarlas. – Glazed

+0

@BLowery, ¿no es necesario especificar HOLDLOCK para mantener el bloqueo exclusivo de la tabla durante la duración de las transacciones? De lo contrario, el bloqueo solo se mantendrá durante la vigencia de la declaración. También puede especificar un nivel de aislamiento de transacción de SERIALIZABLE para forzar un HOLDLOCK en todos los comandos. O bien, ¿el hecho de que está asignando el valor a una variable mantiene automáticamente el bloqueo? Nunca he probado esta técnica exacta. Usualmente hago cosas como 'DELETE FROM Table WITH (TABLOCKX, HOLDLOCK)' y luego rellene la tabla. Sé que se requiere HOLDLOCK allí. – Glazed

0

Acabo de tropezar con un problema similar al trabajar en una tabla de etapas que tenía problemas de escala con bloqueos adecuados.

Donde sea que se haga referencia a su tabla, podría llamar a un procedimiento almacenado que solicite el nombre de la tabla.

El procedimiento almacenado crearía opcionalmente las tablas nuevas o devolverá las tablas antiguas según los parámetros proporcionados.

+0

Lo mejor es proporcionar un código fuente para ilustrar sus respuestas – Mike