[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Вставка в Mysql из txt большого количества данных
linklink26
Есть файл в txt в нем 600000 строчек, их всех надо засунуть в mysql путем долгих издевательств над базой нашел один способ сделать так чтобы скрипт не зависал
и все данные пачками отправлялись в базу но есть одно но.

Сейчас нужно все это дело автоматизировать, я выбрал крон, но естественно он не поддерживает перезагрузку страницы и у меня появился затык, нужно как-то
переработать скрипт чтобы он работал без заголовоков, но возможно есть уже в нете готовые примеры чтобы не изобретать велосипед?

Выкладываю на всякий случай скрипт

<?php
$file_name = 'ad.txt';

$link2 = mysql_connect('localhost','xxxx','xxxxx',TRUE);
mysql_selectdb('xxxxxxx',$link2);


if (($handle_f = fopen($file_name, "r")) !== FALSE)
{
// проверяется, надо ли продолжать импорт с определенного места
// если да, то указатель перемещается на это место

if(isset($_GET['ftell'])){
fseek($handle_f,$_GET['ftell']);
}
$i=0;
if(isset($_GET['x'])){
$x=$_GET['x'];
} else {
$x = 0;
}

// построчное считывание и анализ строк из файла
$idmy = 0;
while ( ($data_f = fgetcsv($handle_f, 1000, "^"))!== FALSE) {

$insert_q = 'INSERT INTO `1s` VALUES ('.$x.',\''.$data_f[0].'\',\''.$data_f[1].'\',\''.iconv("windows-1251","UTF-8",$data_f[2]).'\',\''.iconv("windows-1251","UTF-8",$data_f[3]).'\',\''.iconv("windows-1251","UTF-8",$data_f[4]).'\',\''.iconv("windows-1251","UTF-8",$data_f[5]).'\',\''.$data_f[6].'\',\''.$data_f[7].'\',\''.$data_f[8].'\',\''.$data_f[9].'\',\''.$data_f[10].'\',\''.$data_f[11].'\',\''.$data_f[12].'\',\''.$data_f[13].'\',\''.$data_f[14].'\',\''.$data_f[15].'\',\''.iconv("windows-1251","UTF-8",$data_f[16]).'\')';

mysql_query($insert_q);

if(!strstr($i/5000,'.')){
print 'Importing record #: '.$x.'<br />';
flush();
ob_flush();
}

if($i==20000){
print '<meta http-equiv="Refresh" content="0; url='.$_SERVER['PHP_SELF'].'?x='.$x.'&ftell='.ftell($handle_f).'&path='.$_GET['path'].'">';
exit;
}
$x++;
$i++;
$idmy++;
}

fclose($handle_f);
} else {$err = 1; echo "Не получилось открыть файл";}
?>




Спустя 18 минут, 53 секунды (10.01.2012 - 15:40) killer8080 написал(а):
Цитата (linklink26 @ 10.01.2012 - 14:21)
Сейчас нужно все это дело автоматизировать, я выбрал крон, но естественно он не поддерживает перезагрузку страницы

Ну и нафига нужна перезагрузка страницы? blink.gif

Спустя 4 минуты, 34 секунды (10.01.2012 - 15:45) linklink26 написал(а):
Чтобы пачками вставлять данные и мускул отдыхал, если убирать перезагрузку и потоком закидывать то все виснет.

Спустя 2 минуты, 50 секунд (10.01.2012 - 15:47) killer8080 написал(а):
linklink26
ну так поставь sleep() через N итераций, если боишься сервак перегрузить. И не забудь mysql_ping() чтоб коннект с базой не отвалился.

Спустя 2 минуты, 7 секунд (10.01.2012 - 15:50) killer8080 написал(а):
А вообще лучше наверно использовать LOAD DATA INFILE

Спустя 30 минут, 50 секунд (10.01.2012 - 16:20) linklink26 написал(а):
killer8080
LOAD DATA INFILE не получится, у меня csv файл который я разбиваю в массив и еще еще обрабатываю а в LOAD DATA INFILE другой синтаксис.

Насчет sleep() хорошая идея, попробую.

Спустя 8 минут (10.01.2012 - 16:28) killer8080 написал(а):
Цитата (linklink26 @ 10.01.2012 - 15:20)
LOAD DATA INFILE не получится, у меня csv файл который я разбиваю в массив и еще еще обрабатываю а в LOAD DATA INFILE другой синтаксис.

Почему? LOAD DATA INFILE прекрасно справится с CSV. Откуда изначально берется файл? Может пересмотреть скрипт который его генерит, что бы не было проблем с LOAD DATA INFILE?

Спустя 24 минуты, 50 секунд (10.01.2012 - 16:53) linklink26 написал(а):
Файл берется их 1C его создает сисадмин и выкладывает в таком формате

1|alcatel|экран
2|sony|адаптер
3|htc|шнур питания

с расширением txt но суть в том что он по всем параметрам как csv

Далее я как указано в коде меняю в некоторых полях кодировку на utf-8 и закидываю в базу нумеруя каждую строчку счетчиком в самом начале. Это все тоже в коде в принципе видно.



со sleep вышло
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 65537 bytes) in /var/www/vhosts/

Спустя 6 минут, 33 секунды (10.01.2012 - 17:00) killer8080 написал(а):
Цитата (linklink26 @ 10.01.2012 - 15:53)
нумеруя каждую строчку счетчиком в самом начале.

А не проще было использовать поле с авто инкрементом? Это же первичный ключ, если я правильно понял?
Цитата (linklink26 @ 10.01.2012 - 15:53)
со sleep вышло
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 65537 bytes) in /var/www/vhosts/

где то утечка памяти, покажи целиком скрипт который используешь.
Да и выкинь flush, ob_flush, от них там никакой пользы.

Спустя 3 часа, 29 минут, 6 секунд (10.01.2012 - 20:29) sergeiss написал(а):
Еще от себя добавлю. Про "LOAD DATA INFILE" было уже сказано - поддержу! Если тебе надо переработать файл, то ты его переработай. Но запиши в другой файл, который уже будет четко структурирован для загрузки через LOAD DATA INFILE. В сумме затратишь существенно меньше времени.
И, опять же, насчет автоинкрементного поля тебе уже сказали. Используй его, для того оно и было придумано smile.gif Даже если это и не первичный ключ, то все равно очень полезная штуковина.

Спустя 24 минуты, 32 секунды (10.01.2012 - 20:53) alex12060 написал(а):
я делал недавно проект человеку, ему тоже нужно было залить файл с сотнями тысяч строк
строк
так я просто делил файл на несколько кусков по 1 мегабайту и заливал куски и после заливки удалял.
Все получилось довольно не плохо, работает шустро даже

Спустя 2 минуты, 56 секунд (10.01.2012 - 20:56) sergeiss написал(а):
alex12060 - а зачем надо было делить на куски? Просто не загружалось или таймеры срабатывали какие-то?

Спустя 11 часов, 23 минуты, 40 секунд (11.01.2012 - 08:20) linklink26 написал(а):
killer8080
Вот скрипт со слипами

<?php
$file_name = 'ad.txt';
$link2 = mysql_connect('localhost','xxxx','xxxxx',TRUE);
mysql_selectdb('xxxxxxx',$link2);

if (($handle_f = fopen($file_name, "r")) !== FALSE)
{
// проверяется, надо ли продолжать импорт с определенного места
// если да, то указатель перемещается на это место

if(isset($_GET['ftell'])){
fseek($handle_f,$_GET['ftell']);
}
$i=0;
if(isset($_GET['x'])){
$x=$_GET['x'];
} else {
$x = 0;
}
// построчное считывание и анализ строк из файла
$xs = 0;
$idmy = 0;
while ( ($data_f = fgetcsv($handle_f, 65536, "^"))!== FALSE) {
$data_f[] = $list;
$insert_q = 'INSERT INTO `1s` VALUES ('.$x.',\''.$data_f[$xs][0].'\',\''.$data_f[$xs][1].'\',\''.iconv("windows-1251","UTF-8",$data_f[$xs][2]).'\',\''.iconv("windows-1251","UTF-8",$data_f[$xs][3]).'\',\''.iconv("windows-1251","UTF-8",$data_f[$xs][4]).'\',\''.iconv("windows-1251","UTF-8",$data_f[$xs][5]).'\',\''.$data_f[$xs][6].'\',\''.$data_f[$xs][7].'\',\''.$data_f[$xs][8].'\',\''.$data_f[$xs][9].'\',\''.$data_f[$xs][10].'\',\''.$data_f[$xs][11].'\',\''.$data_f[$xs][12].'\',\''.$data_f[$xs][13].'\',\''.$data_f[$xs][14].'\',\''.$data_f[$xs][15].'\',\''.iconv("windows-1251","UTF-8",$data_f[$xs][16]).'\')';

mysql_query($insert_q);

if(!strstr($i/5000,'.')){
sleep(30);
mysql_ping($link2);
}

$x++;
$i++;
$idmy++;
$xs++;
}
fclose($handle_f);
} else {$err = 1; echo "Не получилось открыть файл";}
?>



Насчет лоад даты надо покопать материал на тему, в принципе идея хорошая.

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

Спустя 1 час, 9 минут, 11 секунд (11.01.2012 - 09:29) killer8080 написал(а):
linklink26
а почему ты работаешь с $data_f, как с двумерным массивом? blink.gif

Спустя 2 часа, 12 минут, 8 секунд (11.01.2012 - 11:41) linklink26 написал(а):
killer8080
И правда это видимо остаточное от старого подхода, убрал, там все равно умирает скрипт, похоже надо разбивать файл на маленькие.

Data load file у меня почему-то не работает, белый экран.

Спустя 1 час, 28 минут, 24 секунды (11.01.2012 - 13:10) sergeiss написал(а):
Цитата (linklink26 @ 11.01.2012 - 12:41)
Data load file у меня почему-то не работает, белый экран.

Ну так время ему надо на загрузку, ежели данных много. Но в любом случае это будет быстрее, чем каждую строку своим ИНСЕРТом делать.

Ты попробуй для начала загрузить этой командой немного строк. Чтобы убедиться, что формат команды верный и всё работает исправно.

Спустя 1 день, 3 часа, 48 минут, 30 секунд (12.01.2012 - 16:58) alex12060 написал(а):
sergeiss

Было дано задание такое smile.gif
Там он говорил, что сервак у него слабый, а предполагается заливка до 50мб файла.

Спустя 2 часа, 47 минут, 21 секунда (12.01.2012 - 19:46) sergeiss написал(а):
Не знаю, что у него там за сервак smile.gif
Но у меня в Постгре заливаются файлы от 1 до 140-150 МБ. При этом в таблицах уже по 10-20-30 миллионов записей, в каждой таблице немало полей... Плюс индексы, которые тоже надо обновить. Общий объем в 400-500 МБ (15 файлов) заливается за 5-10 минут.

Спустя 4 дня, 15 часов, 1 минута, 50 секунд (17.01.2012 - 10:47) linklink26 написал(а):
Вы что-то путаете) Никакого предела по 50 мб у меня нет, файлы закидываю на ftp, сейчас файл весит 80 мб

Вот последняя версия скрипта


<?php
class
File_FGetCSV {

function fgetcsv($f, $length, $d=",", $q='"') {
$list = array();
$st = fgets($f, $length);
if ($st === false || $st === null) return $st;
while ($st !== "" && $st !== false) {
if ($st[0] !== $q) {
# Non-quoted.
list ($field) = explode($d, $st, 2);
$st = substr($st, strlen($field)+strlen($d));
} else {
# Quoted field.
$st = substr($st, 1);
$field = "";
while (1) {
# Find until finishing quote (EXCLUDING) or eol (including)
preg_match("/^((?:[^$q]+|$q$q)*)/sx", $st, $p);
$part = $p[1];
$partlen = strlen($part);
$st = substr($st, strlen($p[0]));
$field .= str_replace($q.$q, $q, $part);
if (strlen($st) && $st[0] === $q) {
# Found finishing quote.
list ($dummy) = explode($d, $st, 2);
$st = substr($st, strlen($dummy)+strlen($d));
break;
} else {
# No finishing quote - newline.
$st = fgets($f, $length);
}
}

}

$list[] = $field;
}
return $list;
}

function fputcsv($f, $list, $d=",", $q='"') {
$line = "";
foreach ($list as $field) {
# remove any windows new lines,
# as they interfere with the parsing at the other end

$field = str_replace("\r\n", "\n", $field);
# if a deliminator char, a double quote char or a newline
# are in the field, add quotes

if(ereg("[$d$q\n\r]", $field)) {
$field = $q.str_replace($q, $q.$q, $field).$q;
}
$line .= $field.$d;
}
# strip the last deliminator
$line = substr($line, 0, -1);
# add the newline
$line .= "\n";
# we don't care if the file pointer is invalid,
# let fputs take care of it

return fputs($f, $line);
}
}


$x=0;
$cfg_File = '/var/www/httpdocs/dump/sklad.txt';

$link2 = mysql_connect('localhost','xxxx','xxxx',TRUE);
mysql_selectdb('xxxxxxx',$link2);
mysql_query("SET NAMES utf8");

if (($handle_f = fopen($cfg_File, "r")) !== FALSE) {
$i=0;
while ($list = File_FGetCSV::fgetcsv($handle_f, 65536, "^")) {

$insert_q = 'INSERT INTO `1s_aug` VALUES ('.$x.',\''.$list[0].'\',\''.$list[1].'\',\''.iconv("windows-1251","UTF-8",$list[2]).'\',\''.iconv("windows-1251","UTF-8",$list[3]).'\',\''.iconv("windows-1251","UTF-8",$list[4]).'\',\''.iconv("windows-1251","UTF-8",$list[5]).'\',\''.$list[6].'\',\''.$list[7].'\',\''.$list[8].'\',\''.$list[9].'\',\''.$list[10].'\',\''.$list[11].'\',\''.$list[12].'\',\''.$list[13].'\',\''.$list[14].'\',\''.$list[15].'\',\''.iconv("windows-1251","UTF-8",$list[16]).'\')';

mysql_query($insert_q);

if(!strstr($i/5000,'.')){
sleep(30);
mysql_ping($link2);
}


$x++;
$i++;

}

fclose($handle_f);
} else {$err = 1; echo "Не получилось открыть файл";}
?>


Все тоже
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 65537 bytes) in /var/www/vhosts/

Спустя 59 минут, 22 секунды (17.01.2012 - 11:47) sergeiss написал(а):
Я так и не пойму, зачем некоторые люди изобретают велосипеды??? Есть команда LOAD DATA INFILE, сделанная специально для таких целей - ну так надо разобраться и сделать всё ОДНОЙ СТРОКОЙ. А то ведь можно и до того добраться, чтобы свою БД "сваять на досуге", ежели будут непонятки какие smile.gif Чего уж мелочиться-то....

Спустя 3 часа, 23 минуты, 31 секунда (17.01.2012 - 15:10) linklink26 написал(а):
Ну не работает у меня load data =)
Решил проблему кстати)
Все стер и сделал простейшую построчную считывалку которая сразу закидывает данные в insert и потом снова =)

Спустя 51 минута, 29 секунд (17.01.2012 - 16:02) sergeiss написал(а):
То, что у тебя оно не работает - это я понял давно уже smile.gif
Но ты все-таки покажи текст запроса, который ты формируешь, и форматы таблицы и данных. Скорее всего, где-то ошибка есть. Если разберешься, то тебе же плюс будет.

Спустя 18 минут, 39 секунд (17.01.2012 - 16:20) asokol написал(а):
1. Перед while поставить LOCK TABLES `1s_aug` WRITE;
2. Вместо SET NAMES `utf8` сделать SET NAMES `cp1251`;
3. Убрать все вызовы iconv;
4. После while поставить UNLOCK TABLES.

5. Почитать про LOAD DATA INFILE тут: http://www.mysql.ru/docs/man/LOAD_DATA.html

Спустя 22 часа, 1 минута, 25 секунд (18.01.2012 - 14:22) linklink26 написал(а):
asokol пасиб, пригодится.

sergeiss у меня с серваком что-то, любой пример с лоэд дата копирую и ничего белая страница, видать в phpini что-то вырублено.

Спустя 47 минут, 41 секунда (18.01.2012 - 15:10) sergeiss написал(а):
Я уже несколько раз написал - покажи код, где ты используешь ЛОАД ДАТА smile.gif Возможно, ты просто что-то не так делаешь. Всё равно же ты как-то адаптируешь код под свой сервер. И при этом можешь где-нибудь "накосячить".

Спустя 1 час, 37 минут, 32 секунды (18.01.2012 - 16:47) killer8080 написал(а):
linklink26
А привилегия FILE к БД вообще есть?

Спустя 1 день, 20 часов, 41 минута, 5 секунд (20.01.2012 - 13:28) linklink26 написал(а):
killer8080
Да там all priveleges

sergeiss
Я уже стер все и не помню что делал) Если найду копию скопирую сюда.

Спустя 5 часов, 2 минуты, 37 секунд (20.01.2012 - 18:31) sergeiss написал(а):
Цитата (linklink26 @ 20.01.2012 - 14:28)
Я уже стер все и не помню что делал) Если найду копию скопирую сюда.

А может быть, это и хорошо, что не помнишь? Сделай заново - возможно, что ты сразу сделаешь правильно и всё получится.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.