Большое количество вставок SQLite с использованием PHP - PullRequest
3 голосов
/ 09 мая 2011

У меня есть около 14000 строк значений, разделенных запятыми, которые я пытаюсь вставить в таблицу sqlite с помощью PHP PDO, например:

<?php
// create a PDO object
$dbh = new PDO('sqlite:mydb.sdb');

$lines = file('/csv/file.txt'); // import lines as array
foreach ($lines as $line) {
    $line_array = (','$line); // create an array of comma-separated values in each line
    $values = '';
    foreach ($line_array as $l) {
        $values .= "'$l', ";
    }
    substr($values,-2,0); // get rid of the last comma and whitespace
    $query = "insert into sqlite_table values ($values)"; // plug the value into a query statement
    $dbh->query($query); // run the query
}

?>

Этот запрос занимает много времени, и чтобы выполнить его без перерыва, мне пришлось бы использовать PHP-CLI. Есть ли лучший (более быстрый) способ сделать это?

Ответы [ 4 ]

20 голосов
/ 09 мая 2011

Вы увидите хороший выигрыш в производительности, обернув вставки в одну транзакцию. Если вы этого не сделаете, SQLite рассматривает каждую вставку как свою собственную транзакцию.

<?php
// create a PDO object
$dbh = new PDO('sqlite:mydb.sdb');

// Start transaction
$dbh->beginTransaction();
$lines = file('/csv/file.txt'); // import lines as array
foreach ($lines as $line) {
    $line_array = (','$line); // create an array of comma-separated values in each line
    $values = '';
    foreach ($line_array as $l) {
        $values .= "'$l', ";
    }
    substr($values,-2,0); // get rid of the last comma and whitespace
    $query = "insert into sqlite_table values ($values)"; // plug the value into a query statement
    $dbh->query($query); // run the query
}
// commit transaction
$dbh->commit();

?>
2 голосов
/ 09 мая 2011

Начать транзакцию перед циклом и зафиксировать ее после цикла
Теперь, когда ваш код работает, он запускает транзакцию при каждой вставке

1 голос
/ 04 октября 2012

Если вам нужна более быстрая скорость, используйте команду prepare / fetch, чтобы движку SQL не приходилось каждый раз анализировать текстовую строку.

$name = $age = '';
$insert_stmt = $db->prepare("insert into table (name, age) values (:name, :age)");
$insert_stmt->bindValue(':name', $name);
$insert_stmt->bindValue(':age', $age);

// do your loop here, like fgetcsv
while (get the data) {
list($name, $age) = split(',', $string);
$insert_stmt->execute();
}

Это нелогично, чтоВы делаете связывание вне цикла, но это одна из причин, почему этот метод такой быстрый, вы в основном говорите: «Выполните этот предварительно скомпилированный запрос, используя данные из этих переменных».Так что даже не нужно перемещать данные внутри.И вы хотите избежать повторного разбора запроса, что является проблемой, если вы используете что-то вроде «вставить в таблицу (имя) значения ('$ name')», каждый запрос отправляет всю текстовую строку в базу данных для повторного анализа.parsed.

Еще одна вещь, чтобы ускорить его - обернуть весь цикл в транзакцию, а затем зафиксировать транзакцию, когда цикл завершится.

1 голос
/ 09 мая 2011

С FAQ по SQLlite :

Скорость транзакции ограничена скоростью диска, потому что (по умолчанию) SQLite фактически ждет, пока данные действительно безопасно хранится на диске поверхность до транзакции полный. Таким образом, если вы вдруг потеря питания или если ваша ОС падает, ваш данные все еще в безопасности. Подробнее читайте об атомном коммите в SQLite .. [...]

Другой вариант - запустить PRAGMA синхронно = OFF. Эта команда будет заставить SQLite не ждать данных достичь поверхности диска, которая будет сделать операции записи кажутся намного быстрее. Но если вы потеряете власть в середина сделки, ваш Файл базы данных может быть поврежден.

Я бы сказал, что вам нужен последний абзац.

РЕДАКТИРОВАТЬ : Нет уверенности в этом, но я считаю, что использование sqlite_unbuffered_query () должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...