Порционный импорт CSV в MySQL на PHP

109
17 декабря 2021, 10:30

Как сделать импорт большого csv файла (порядка 100мб)

Что бы при каждом запуске скрипта импортировалось по 1000 строк

Есть такой код, помогите доработать, или может есть у кого готовое решение

<?php 
$host      = 'localhost'; 
$db_name   = 'db_name'; 
$db_user   = 'db_user'; 
$db_passwd = 'db_passwd'; 
$file      = 'file.csv'; 
$delimiter = ';'; 
$verbose   = true; 
 
try { 
    $db = new PDO("mysql:host=$host;dbname=$db_name", $db_user, $db_passwd, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); 
	$db->exec("set names utf8"); 
    $stmt = $db->prepare("INSERT INTO oc_review (`id`, `text`) VALUES (?, ?) "); 
 
    if (!file_exists($file)){ 
        throw new Exception("File $file not found!"); 
    } 
    $f = fopen($file, 'r+'); 
 
    $data = array(); 
    while($data[]=fgetcsv($f, 0, $delimiter)){} 
 
    if (empty($data)) { 
        throw new Exception("Empty data. Check the source file."); 
    } 
    $i=0; 
    foreach ($data as $entry) { 
        if (!is_array($entry) || empty($entry[0])) { 
            continue; 
        } 
        if ($verbose){ 
            print "\nProcessing entry ID: ". $entry[0]; 
        } 
        $stmt->execute($entry); 
        $i++; 
    } 
    print "\n\n$i rows were successfully processed"; 
 
} 
catch (Exception $e){ 
    print "Error: " . $e->getMessage(); 
}

Answer 1

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

// Например вот так можно читать файл
$linecount = 0;
$buffer = [];
$file = @fopen("yourfilepath", "r");
while(!feof($file)) { 
    if($linecount > 999){
        //Вставить в базу работаем с массивом буффер
        //Обнуляем переменные
        $linecount = 0;
        $bufer = [];
    }
    $buffer[] = fgets($file);
    $linecount++;
} 
fclose($file); 
//Или вот так например
$startline = $_POST['startln'];
$buffer = [];
$linecount = 0;
$file = @file("yourfilepath");
while($linecount < $startline+999){
    $i = $startline+$linecount;
    if($s=$file[$i]){
        $buffer[] = $s;
        $linecount++
    }
    else{
        break;
    }
}
//Как написал Эдуард ниже в комментариях, проверяем буффер на пустосту
if (! empty($buffer)){
//Сделать что то с массивом buffer
}

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

Answer 2

Читать не вариант - каждый раз будет загрузка всех 100мб.

Правильнее разбить эти 100мб на части - например, как раз по 1000 строк чтобы было и импортировать поочередно - например, по имени файла, в котором содержится нумерация.

READ ALSO
Работа с аргументами функции PHP

Работа с аргументами функции PHP

Есть функция f() с 3 аргументамиНад каждым аргументом выполняется операция (одна и та же)

105
Добавление данных с форму в mysql

Добавление данных с форму в mysql

Итак, проблема следующая: у меня есть 2 страницы с формами, чтобы добавить данные в mysqlДанные прекрасно добавляются, но дело в следующем: на 1-ой...

173
PRIMARY KEY ПО 2 полям

PRIMARY KEY ПО 2 полям

Есть таблица с столбцами: product_id, date, price

112