2009-07-30 21 views
6

Tengo un servidor MS SQL con un servidor MySQL vinculado. Necesito sincronizar parcialmente una tabla entre los dos servidores. Esto se realiza en tres pasos y se basa en una condición:Actualizar la consulta en la tabla MySQL vinculada de SQL Server

  1. Eliminar todas las filas de la tabla de MySQL que no satisfacen la condición

  2. Insertar todas las nuevas filas en la tabla de MySQL que satisfacen la condición

  3. actualización de todas las filas del servidor MySQL que satisfacen la condición y tienen diferentes datos entre MySQL y SQL Server

Los pasos 1 y 2 siempre se ejecutan sin problemas. Pero el paso 3 no se ejecutará si hay algo que actualizar. La consulta falla con la siguiente excepción: El conjunto de filas utilizaba simultaneidad optimista y el valor de una columna se modificó después de que la última fila se haya recuperado o resincronizado por última vez.].

Esta es la consulta que se ejecuta:

update mysqlserver...subscribers 
set Firstname = Voornaam, 
    Middlename = Tussenvoegsel, 
    Surname = Achternaam, 
    email = e-mail 
from mysqlserver...subscribers as b, tblkandidaat 
where (b.kandidaatid = tblkandidaat.kandidaatid) and 
    (tblkandidaat.kandidaatid in (
    select subsc.kandidaatid 
    from mysqlserver...subscribers subsc inner join tblKandidaat 
     on (subsc.kandidaatid=tblKandidaat.kandidaatid) 
    where (subsc.list=1) and 
     ((subsc.firstname COLLATE Latin1_General_CI_AI <> Voornaam 
     or (subsc.middlename COLLATE Latin1_General_CI_AI <> Tussenvoegsel) 
     or (subsc.surname COLLATE Latin1_General_CI_AI <> tblKandidaat.Achternaam) 
     or (subsc.email COLLATE Latin1_General_CI_AI <> tblKandidaat.e-mail)) 
)); 

Alguien tiene una idea acerca de cómo evitar esto?

+0

Perdón por el final de esta pregunta. Usé la solución propuesta por Emtucifor y funcionó. ¡Gracias a todos! – Birger

Respuesta

2

Intentar esta consulta en su lugar:

update b 
set 
    Firstname = Voornaam, 
    Middlename = Tussenvoegsel, 
    Surname = Achternaam, 
    email = e-mail 
from 
    mysqlserver...subscribers b 
    inner join tblkandidaat k on b.kandidaatid = k.kandidaatid 
where 
    b.list=1 
    and (
     b.firstname COLLATE Latin1_General_CI_AI <> k.Voornaam 
     or b.middlename COLLATE Latin1_General_CI_AI <> k.Tussenvoegsel 
     or b.surname COLLATE Latin1_General_CI_AI <> k.Achternaam 
     or b.email COLLATE Latin1_General_CI_AI <> k.e-mail 
    ) 
  1. que es mejor la práctica de utilizar ANSI se une adecuadamente y separar condiciones de combinación de condiciones WHERE.

  2. Es más fácil usar alias para todas las tablas en lugar de nombres de tablas largas en toda la consulta.

  3. Es mejor utilizar los alias para todas las referencias de columnas en lugar de dejarlos en blanco. No solo es un buen hábito y hace que las cosas sean más claras, sino que también puede evitar algunos errores muy desagradables en las referencias de tablas internas y externas.

  4. Si el rendimiento también es un problema: las uniones de servidor vinculadas a veces pasan al procesamiento de fila por fila en el motor del proveedor de datos de base de datos. He encontrado casos en los que dividir parte de una combinación compleja en un servidor vinculado en una unión regular seguida de una aplicación cruzada redujo enormemente las filas innecesarias que se estaban obteniendo y mejoró enormemente el rendimiento. (Esto básicamente era hacer una búsqueda de marcador, también conocido como un análisis de índice no agrupado seguido por búsqueda de índice agrupado utilizando esos valores). Si bien esto puede no encajar perfectamente con el funcionamiento de MySql, vale la pena experimentar con él. Si puede hacer cualquier tipo de rastreo para ver las consultas reales que se realizan en el lado de MySql, puede obtener información sobre otros métodos para aumentar el rendimiento.

  5. Otra idea para mejorar el rendimiento es copiar los datos remotos localmente en una tabla temporal y agregar una columna ActionRequired. A continuación, actualice la tabla temporal para que se vea como debería, colocando 'U', 'I' o 'D' en ActionRequired, luego realice la fusión/inserción en el servidor vinculado con una equijoins simple en la clave primaria, utilizando ActionRequired. Se debe prestar especial atención a las posibles condiciones de carrera en las que la base de datos remota podría actualizarse durante el procesamiento.

  6. Ten cuidado con los nulos ... ¿son todas esas columnas las que estás comparando que no admiten nulos?

0

Puede intentar crear una segunda tabla en mysql, haciendo una inserción desde sql-server en esa tabla vacía para todas las líneas modificadas y haciendo el Paso 3 entre las dos tablas de mysql.

0

intenta no utilizar la subconsulta en su sentencia where. La subconsulta puede devolver más de una fila, y luego recibiste el error.

+0

Está usando el operador 'IN'. Él quiere múltiples filas. Aunque creo que el diablo está en los detalles y el uso de la subconsulta es realmente el problema. –

0

intente crear una vista que tenga la fuente, el destino y la columna has_changed entre y se han unido las tablas vinculadas. entonces se puede emitir consulta

actualización destino definido vi_upd_linkedtable = fuente de donde has_changed = 1

0

Se trata de un disparo en la oscuridad, pero trate de añadir FOR UPDATE o LOCK IN SHARE MODE hasta el final de la consulta subselección. Esto le dirá a MySQL que está tratando de seleccionar cosas para una actualización dentro de su transacción y debería crear un bloqueo de escritura a nivel de fila durante el select en lugar de durante el update.

De 13.2.8.3. SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE Locking Reads:

SELECT ... LOCK IN SHARE MODE establece un bloqueo en modo compartido en las filas leídas. Un bloqueo de modo compartido habilita otras sesiones para leer las filas, pero no a modificarlas. Las filas leídas son las últimas disponibles, por lo que si pertenecen a otra transacción que aún no se ha comprometido , los bloques leídos hasta que finalice la transacción .

0

Para las filas donde los nombres son los mismos, el update no es operativo.

No guarda ningún trabajo al intentar filtrar las filas en las que son iguales, porque los datos todavía tienen que ser comparados a través del enlace. Entonces no puedo ver ningún beneficio para la subconsulta.

Por lo tanto la consulta se puede simplificar mucho:

update mysqlserver...subscribers 
set Firstname = Voornaam, 
    Middlename = Tussenvoegsel, 
    Surname = Achternaam, 
    email = e-mail 
from mysqlserver...subscribers as b join tblkandidaat 
    on b.kandidaatid = tblkandidaat.kandidaatid; 
where b.list = 1; 

La eliminación de la sub consulta podría hacer que su el problema de bloqueo desaparezca. MySQL tiene algunos problemas que combinan un select y un update en la misma tabla en una consulta determinada.

0

Pruebe esto. Escribí varios de estos hoy.

update b 
set 
    Firstname = Voornaam, 
    Middlename = Tussenvoegsel, 
    Surname = Achternaam, 
    email = e-mail 
from 
    mysqlserver...subscribers b 
    inner join tblkandidaat k on b.kandidaatid = k.kandidaatid 
where 
    b.list=1 
    and (
     ISNULL(b.firstname,'') COLLATE Latin1_General_CI_AI <> ISNULL(k.Voornaam,'') 
     or ISNULL(b.middlename,'') COLLATE Latin1_General_CI_AI <> ISNULL(k.Tussenvoegsel,'') 
     or ISNULL(b.surname,'') COLLATE Latin1_General_CI_AI <> ISNULL(k.Achternaam,'') 
     or ISNULL(b.email,'') COLLATE Latin1_General_CI_AI <> ISNULL(k.e-mail,'') 
    ) 

El uso de ISNULL le permite anular sus columnas.

Cuestiones relacionadas