Кажется, что может быть проще перегона данных 1 к 1 из одной релятивной базы в другую? Просто делаеш селект из одной и инсерт в другую. Но тут возникает проблемма с тем, как выбрать например записи с 900 до 1000. Большенство програмистов сразу же предложат запрос SELECT FIRST 1000 SKIP 900 …. (так как в firebird нет LIMIT) и такой запрос выполнится очень быстро, но только при маленьких объёмах данных (до 1 млн. записей). А что делать в случае, если нам необходимо сделать выборку 10 последних строк из 10 000 000 записей? Такой запрос будет выполняться уже около 52 секунд.
Как вы уже могли догадаться, есть и другой метод выборки записей – это выборка по индексу. В данной статье именно такой алгоритм я и хочу описать.
Для подключения к базам данных воспользуемся стандартными регулярными выражениями php.
Для работы нам понадобытся библиотеки php5-ibase и php5-mysql.
Описание самого процесса перегона базы я вставлю в коментарии в коде скрипта.
Предположим, что у нас есть 2 одинаковые по структуре базы данных firebird и mysql. они имеют одну таблицу с полнями
id, key, value где в обеих таблицах на поля кинуты индексы а на поле key кинут уникальный индекс. Таблицу назовём my_tbl
Вот пример кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <?php ini_set('disply_error', E_ALL); //Сначала зададим параметры баз данных согласто документации $fb_host = 'localhost:база'; $fb_username='SYSDBA'; $fb_password='пароль'; $mysql_host = 'localhost'; $mysql_username='root'; $mysql_password='пароль'; $mysql_db='база'; // далее нам необходимо подключиться к базам данных $dbh = ibase_connect ( $fb_host, $fb_username, $fb_password ) or die ("Firebird умер"); $dbm = mysql_connect ( $mysql_host,$mysql_username,$mysql_password) or die("MySQL умерла"); $tr = ibase_trans (IBASE_NOWAIT, IBASE_READ, IBASE_CONCURRENCY, $dbh); //выбираем БД и кодировку символов. Обратите внимание, на то, что в фаербёде //база данных выбирается иначе чем в mysql, в фаербёде она указывается при //открытии стэка(подключении) mysql_select_db($mysql_db); mysql_query("SET NAMES 'cp1251'"); //подсчитаем общее количество записей в исходной БД $stmt = 'select count(*) from my_tbl'; $sth = ibase_query($dbh, $stmt); while ($row = ibase_fetch_assoc($sth)) { $count = intval($row['COUNT']) ; } //теперь нам нужно соответственно установить начальное и конечное положение индекса //так как мы будем выбирать с нуля то $mincnt будет равно 0 $mincnt=0; //определяем максимальное число уникальных строк $stmt = 'select max(key) from my_tbl'; $sth = ibase_query($dbh, $stmt); while ($row = ibase_fetch_assoc($sth)) { $maxcnt = intval($row['MAX']); } $cnt=$mincnt; $rcnt=0; $rcnts=0; //начинаем переборку записей и выборку из индекса по 50000 записей вставляя их в mysql while ($rcnts<$count) { $stmt = 'select count(*) from my_tbl where key BETWEEN (' .$cnt. ') AND (' .($cnt+49999). ') '; $sth = ibase_query($tr,$stmt); while ($row = ibase_fetch_assoc($sth)) { $rcnt = intval($row['COUNT']); } $stmt = 'SELECT * FROM my_tbl WHERE key BETWEEN (' .$cnt. ') AND (' .($cnt+49999). ') ORDER BY key'; $sth = ibase_query($tr, $stmt); |
Обратите внимание на то, как осушествляется перебор по индексу. мы берём из индекса кусками строки и потом генерируем обин пакет из общего числа строк. Кстати, запрос $stmt = ‘SELECT * FROM my_tbl WHERE key BETWEEN (‘ .$cnt. ‘) AND (‘ .($cnt+49999). ‘) ORDER BY key’; может вернуть нам не обязательно 50 000 строк, именно по этому мы и делаем проверку циклом while ($rcnts<$count) то есть итерации будут происходить до тех пор, пока количество выбранных из индекса строк не достигнет общего количества строк.
Данный способ является наиболее эфективным и быстродейственным. По сравнительным результатам вариант конвертирования через first x skip y на 10 000 000 записей занял бы неделю, а написанный мною вариант конвертирует базу за 30 минут и соответственно эфективнее первого метода в 336 раз.
Из Firebird/Interbase в MySQL