Mysql Синхронизация 2-х таблиц из разных БД

stwa

Новичок
Всем привет.
Есть 2 БД.
Одна MySQL, другая на MS SQL
В MS SQL есть хранимая процедура, которая возвращает содержимое некой таблицы.
Аналогичная таблица с такими же полями есть в MySQL.
Задача - обновить все строки в таблице MySQL, если они отличаются от строк в таблице на MS SQL.

Пока интересует 1 часть задачи, а именно как найти строки, которые надо обновить.
Кол-во записей в каждой таблице порядка 300 тыс., тестирую на тестовой базе с кол-вом записей в 30 тыс.
В каждой таблице есть уникальное поле, по которому можно сравнивать записи
Работаю через PDO.

Первое что приходит в голову - получить таблицы из обеих БД с помощью fetchAll в массивы, а потом уже сравнивать эти массивы.
После сравнения у нас будет массив ключей строк (индексов) из таблицы первоисточника (MS SQL), которые отличаются от второй таблицы.
PHP:
//msRows - массив, полученный с помощью fetchAll из MS SQL
//myRows - массив, полученный с помощью fetchAll из MySQL

        $foundKeys = array(); //массив ключей строк, которые надо обновить
        foreach ($msRows as $key => $msRow) {
            if(!in_array($msRow, $myRows))
                $foundKeys[] = $key;
        }
при выполнении через пару минут получаю ошибку:
Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2006 MySQL server has gone away' in...

ошибка возникает вот из-за этой конструкции:
PHP:
in_array($msRow, $myRows)
потому что простая итерация по массиву
PHP:
        foreach ($msRows as $key => $msRow) {
        }
отработает без ошибок.

Больше всего меня смущает, что ошибка в MySQL
Погуглив, нашел советы по увеличению max_allowed_packet в настройках mysql.

Поэтому 2 вопроса:
1. как работает fetchAll в PDO? Я считал, что выбираются все записи и сохраняются в массив. Потом можно работать с массивом и обращений к базе не будет. Но только я делаю поиск по массиву выскакивает ошибка MySQL

2. Правильный ли путь я вообще выбрал, выбирая сначала ВСЕ записи в массив?

Может кто уже решал подобную задачу, откликнитесь
 

WMix

герр M:)ller
Партнер клуба
можно на уровне ODBC подключиться к MySQL из MS SQL а далее работать как с таблицами MS SQL
те. insert select

(правда я не знаю как сейчас но годиков 10 назад это работало)
 

stwa

Новичок
Не смогу даже попробовать, т.к. в MS SQL права только на запуск хранимой процедуры, которая возвращает датасет.
Да и MySQL с PHP находятся на unix-сервере, поэтому никакого ODBC нет.
 

hell0w0rd

Продвинутый новичок
А почему нельзя проверять по частям? LIMIT 0, 1000 => 1000, 2000 и тд?)
 

stwa

Новичок
Решил задачку, даже 2 -мя способами:
1 вариант: оставил fetchAll для обеих баз
привел массив строк из MySQL к такому виду:
PHP:
$myRows = array(
    'unique_name1' => array(
        'name1_1' => 'value1_1',
        'name1_2' => 'value1_2',
    ),
    'unique_name2' => array(
        'name2_1' => 'value2_1',
        'name2_2' => 'value2_2',
    ),
);
т.е. вынес уникальное поле в ключ массива.
а затем так:
PHP:
foreach ($msRows as $key => $msRow) {
    if(!array_key_exists($msRow['unique_name'], $myRows))
        $foundKeys[] = $key;
}
все отработало за доли секунды без ошибок.

Но куда более интересен для моего случая 2-й вариант:
сделал fetchAll только для MS SQL, а выборку из MySQL вообще не делал

базу синхронизировал при помощи простого запроса INSERT:
PHP:
INSERT INTO `table` (`a`, `b`, `c`) VALUES
(1, 2, 3), (4, 5, 6), (7, 8, 9)
ON DUPLICATE KEY UPDATE `b`=VALUES(`b`), `c`=VALUES(`c`);
где `a` - это уникальный ключ, а ON DUPLICATE KEY UPDATE говорит MySQL, что если в базе уже есть такая запись с уникальным полем, то надо делать не INSERT, а UPDATE.
Причем физическое обновление полей будет только тогда, когда они отличаются.

Вот так все просто.
Может кому пригодится...
 

stwa

Новичок
а если удалили, то надо аналогично первому варианту найти id-шники записей, которые надо удалить
мне просто не надо удалять, надо обновить и добавить новые
 
Сверху