@BigCrazyCat

Как вставить 1M+ строк в MySQL?

Сайт на Yii2. PHP 7.2, MySQL 5.7.
Использую следующий код для вставки новой строки:
$command = Yii::$app->db->pdo->prepare("INSERT INTO product (
    gs_id, available, shop_id, product_key,
    article, category_id, picture, thumbnail,
    original_picture, name, description, brand_id,
    model, old_price, price, url, destination_url
 ) VALUES (
    :gs_id, :available, :shop_id, :product_key,
    :article, :category_id, :picture, :thumbnail,
    :original_picture, :name, :description, :brand_id,
    :model, :old_price, :price, :url, :destination_url
)", [\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false]);

$command->bindParam(':gs_id', $gs_id);
$command->bindParam(':available', $available);
...
$gs_id = 1;
$available = 1;
...
$command->execute();


Уже на 200000-ой записи процесс Апача потреблят около 1.5 Гб оперативной памяти. Без сохранения в БД - ~100 Мб. Только сохранение данных, обработки после нет.
Есть идеи?
  • Вопрос задан
  • 646 просмотров
Решения вопроса 1
Stalker_RED
@Stalker_RED
LOAD DATA INFILE '/tmp/test.txt' INTO TABLE test
https://dev.mysql.com/doc/refman/8.0/en/load-data.html

Или если из дампа
mysql -u dbLogin -p dbName < somefile.sql
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@Fixid
Используйте bulk insert
Хардкор вариант: сгенерировать bulk insert и записать в файл. Потом потоком перенаправить в mysql
Ответ написан
@Wol_fi
php, js, mysql, highload
Ну во первых - забудьте про использование php при таких количествах данных. Php не самый оптимальный вариант когда кол-во оперативной памяти ограничено. Здесь гораздо лучше использовать тот же mysql-client или mysqldump. Естественно вставлять лучше одним запросом. Во вторых - саму СУБД тоже надо подготовить к записи такого кол-ва данных. Этого обычно нигде не пишут, но mysql не пригоден для использования "из коробки". Для начала можно попробовать отключить бинарный лог(если нет необходимости в репликации и т.п.). Это освободит драгоценные иопсы на ЖД, особенно если на сервере присутствует не только одна база данных. Если таблица innodb(или его форк) - то настроить необходимые переменные этого движка(количество потоков записи, размеры всяческих буферов, логирование транзакций и т.д.) исходя из возможностей сервера. Все вместе по итогу даст и прирост скорости выполнения запроса и оптимизацию использования серверных ресурсов.
Ответ написан
Комментировать
@BigCrazyCat Автор вопроса
Реализовал через LOAD DATA INFILE, но c потреблением памяти стало еще хуже.
Теперь на 50000 строк приходится столько же, как раньше на 250000.
Код:
$dataString .= "$gs_id|$available|$shop_id|$product_key|$article|$category_id|$picture|$thumbnail|$original_picture|$name|$description|$brand_id|$model|$old_price|$price|$url|$destination_url\n";
$dataPath = str_replace('\\', '/', Yii::$app->basePath)  . '/products/products.txt';
$dataFile = fopen($dataPath, 'w');
fwrite($dataFile, $dataString);
fclose($dataFile);
unset($dataString, $dataFile);

Yii::$app->db->createCommand('SET GLOBAL local_infile = true;')->execute();
Yii::$app->db->createCommand("
            LOAD DATA LOCAL INFILE '$dataPath'
            INTO TABLE product
            FIELDS TERMINATED BY '|'
            (
                gs_id,available,shop_id,product_key,article,category_id,
                picture,thumbnail,original_picture,name,description,brand_id,
                model,old_price,price,url,destination_url
            )
 ")->execute();
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы