@AlikDex

Подкиньте идею оптимизации вот этого чуда?

Значит так. Есть метод, который сканит урл некоего сайта, тащит к себе csv файл и постепенно добавляет в базу или обновляет существующие записи из него. Файл большой(порядка 500к записей на ~660мб), поэтому разбито все на небольшие кусочки и вызывается раз в n минут. Суть надеюсь понятна. Подкиньте идей по оптимизации? (особенно интересует внутренний цикл с запросом =))
/**
 *	Сканирует CSV файл и полученные данные записывает в базу данных.
 *	Строка в файле: id|title|duration|post_date|link|screenshots_prefix|screenshots|custom1|custom2|custom3
 *	
 *	@param int $numFieldParse количество строк, добавляемых\обновляемых за одну транзакцию.
 *
 *	@return array: success - статус завершения, reason - результат выполнения.
 */	
public function parseCSV($numFieldParse = 300)
{
	if (! $this->init)
		return false;

	$csv_data = [];
	$csvFile = _LOG_DIR_ . "/em_parse.csv";

	if ($numFieldParse == 'all') {
		$numFieldParse = 9999999;
		unlink ($csvFile);
	}

	$csv_data = file($csvFile);

	if (empty($csv_data) || !file_exists($csvFile)) {
		$file = $this->params['csv_url'];

			// загрузим файл построчно
		$csv_data = file($file);

		if (false === $csv_data)
			return ['success' => false, 'reason' => "CSV файл  не доступен для скачивания"];

			// если в настройках указано "убрать первую линию, с названиями - убираем ее"
		if ($this->params["skip_csv_first_line"] == 1)
			array_shift($csv_data);

	}

		// Вырежем некоторое количество строк для текущей обработки.
	if (count($csv_data) > $numFieldParse ) {
		$csv = array_splice($csv_data, 0, $numFieldParse);
	} else {
		$csv = $csv_data;
		$csv_data = [];
	}
		
		// Затем запишем остатки в файл, из него в будем парсить следующие проходы.
	if (false === file_put_contents($csvFile, $csv_data))
		return ['success' => false, 'reason' => "Невозможно записать CSV файл в директорию <b>/runtime/embeds</b>"];
	
	$count = 0; // сколько вставилось или обновилось записей.
	$chunckedCsv = [];

	if (count($csv) >= 100 )
		$chunckedCsv = array_chunk($csv, 100);
	else
		$chunckedCsv[] = $csv;

	unset ($csv, $csv_data);

	foreach ($chunckedCsv as $csv) {

		$this->pdo->beginTransaction();

		foreach  ($csv as $csvRow) {	// парсим строчки файла и нужные переменные записываем в базу.

			$item = str_getcsv($csvRow, "|");

			$post['embed_id'] 		= intval(@$item[0]);
			$post['title']			= str_replace("'", '"', @$item[1]);
			$post['duration'] 		= @$item[2]; // в секундах
			$post['date'] 			= @$item[3];		
			$post['source_link'] 	= @$item[4];			
			$post['images']			= $this->getScrArray(@$item[5],@$item[6]);			
			$post['status']			= "0";
			$post['video_format']	= $this->videoFormat;

			$sql = "INSERT INTO `" . PREFIX . "_embed_manager` (`embed_id`, `title`, `duration`,`date`,`source_link`,`images`,`status`,`video_format`) 
					VALUES ('{$post['embed_id']}', '{$post['title']}', '{$post['duration']}', '{$post['date']}', '{$post['source_link']}', '{$post['images']}', '{$post['status']}', '{$post['video_format']}') 
					ON DUPLICATE KEY UPDATE `title`='{$post['title']}', `duration`='{$post['duration']}', `date`='{$post['date']}', `source_link`='{$post['source_link']}', `images`='{$post['images']}', `video_format`='{$post['video_format']}'";
			$stmt = $this->pdo->query($sql);				

			if ($stmt && $stmt->rowCount() > 0) {	
				$count += $stmt->rowCount();
			}

			unset($post);
		}

		$this->pdo->commit();
	}
	
	$reason = "Добавлено новых записей: <b>" . $count . "</b>шт.";
	return ['success' => true, 'reason' => $reason];
}
  • Вопрос задан
  • 276 просмотров
Решения вопроса 1
VladimirAndreev
@VladimirAndreev
php web dev
INSERT INTO ... VALUES('1'),('2'),('3');

намного быстрее, чем 3 отдельных вставки.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
webinar
@webinar Куратор тега PHP
Учим yii: https://youtu.be/-WRMlGHLgRg
Отдельно брать и сохранять csv. Потом ставить сервер очередей и обрабатывать.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы