Обновить запрос к связанной таблице MySQL с SQL Server - PullRequest
6 голосов
/ 30 июля 2009

У меня есть MS SQL Server со связанным сервером MySQL. Мне нужно частично синхронизировать таблицу между двумя серверами. Это делается в три этапа и на основе условия:

  1. Удалить все строки из таблицы MySQL, которые не удовлетворяют условию

  2. Вставьте все новые строки в таблицу MySQL, которые удовлетворяют условию

  3. Обновление всех строк на сервере MySQL, которые удовлетворяют условию и имеют разные данные между MySQL и SQL Server

Шаги 1 и 2 всегда выполняются без проблем. Но шаг 3 не будет выполняться, если есть что обновить. Сбой запроса со следующим исключением: Набор строк использовал оптимистичный параллелизм, и значение столбца было изменено после последней выборки или повторной синхронизации содержащейся строки.].

Это запрос, который выполняется:

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))
  ));

У кого-нибудь есть идеи о том, как это предотвратить?

Ответы [ 7 ]

2 голосов
/ 15 января 2010

Попробуйте вместо этого запрос:

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. Рекомендуется использовать соединения ANSI и правильно отделять условия соединения от условий WHERE.

  2. Лучше использовать псевдонимы для всех ваших таблиц вместо длинных имен таблиц в запросе.

  3. Лучше использовать псевдонимы для всех ссылок на столбцы, а не оставлять их пустыми. Это не только хорошая привычка, которая проясняет ситуацию, но и позволяет избежать некоторых очень неприятных ошибок в ссылках на внутренние и внешние таблицы.

  4. Если производительность также является проблемой: присоединение к связанному серверу иногда переходит к построчной обработке в механизме поставщика данных БД. Я обнаружил случаи, когда разбиение части сложного соединения на связанном сервере на обычное соединение с последующим перекрестным применением значительно уменьшало выборку ненужных строк и значительно улучшало производительность. (По сути, это был поиск закладок, то есть сканирование некластеризованного индекса с последующим поиском кластерного индекса с использованием этих значений). Хотя это может не совсем соответствовать тому, как работает MySql, с ним стоит поэкспериментировать. Если вы можете выполнить любой вид трассировки, чтобы увидеть фактические запросы, выполняемые на стороне MySql, вы можете получить представление о других методах, используемых для повышения производительности.

  5. Еще одна идея для повышения производительности - скопировать удаленные данные локально во временную таблицу и добавить столбец ActionRequired. Затем обновите временную таблицу так, чтобы она выглядела так, как нужно, поместив «U», «I» или «D» в ActionRequired, а затем выполните объединение / перенос на связанном сервере с помощью простых эквивалентных операций на первичном ключе, используя ActionRequired. Внимательно следите за возможными состояниями гонки, при которых удаленная база данных может обновляться во время обработки.

  6. Остерегайтесь пустых значений ... все эти столбцы, которые вы сравниваете, не обнуляются?

0 голосов
/ 20 января 2010

Попробуй это. Я написал несколько из них сегодня.

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,'')
   )

Использование ISNULL позволяет обнулить столбцы.

0 голосов
/ 14 января 2010

Для строк, имена которых совпадают, update - это запрет.

Вы не сохраняете какую-либо работу, пытаясь отфильтровать строки, в которых они совпадают, поскольку данные по-прежнему необходимо сравнивать по ссылке. Так что я не вижу никакой пользы для подзапроса.

Поэтому запрос может быть значительно упрощен:

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;

Устранение подзапроса может решить проблему блокировки. В MySQL есть некоторые проблемы, связанные с объединением select и update в одной таблице в данном запросе.

0 голосов
/ 11 января 2010

Это выстрел в темноте, но попробуйте добавить FOR UPDATE или LOCK IN SHARE MODE в конец вашего запроса на выборку. Это сообщит MySQL, что вы пытаетесь выбрать материал для обновления в вашей транзакции, и должно создать блокировку записи на уровне строк во время select, а не во время update.

С 13.2.8.3. ВЫБРАТЬ ... ДЛЯ ОБНОВЛЕНИЯ и ВЫБРАТЬ ... БЛОКИРОВКА В РЕЖИМЕ ОБМЕНА Блокировка считывает :

SELECT ... LOCK IN SHARE MODE устанавливает общая блокировка режима чтения строк. блокировка общего режима позволяет другим сеансы читать строки, но не изменить их. Прочитанные строки являются последний доступный, так что если они принадлежат еще одна транзакция, которая еще не совершено, чтение блоков до этого транзакция заканчивается.

0 голосов
/ 03 января 2010

попробуйте создать представление, в котором есть столбцы source, destination и has_changed между и к которым присоединены связанные таблицы. тогда вы можете оформить запрос

обновить vi_upd_linkedtable установить назначение = источник, где has_changed = 1

0 голосов
/ 02 января 2010

старайтесь не использовать подзапрос в вашем операторе where. Подзапрос может вернуть более одной строки, и тогда вы получите ошибку.

0 голосов
/ 31 июля 2009

Вы можете попробовать создать вторую таблицу в mysql, сделать вставку из sql-сервера в эту пустую таблицу для всех измененных строк и выполнить шаг 3 между двумя таблицами mysql.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...