Лучшая практика: файл MySQL Импорта в PHP; запросы разделения

Да. std::exception основной класс исключений в библиотеке стандарта C++. Можно хотеть избегать использования строк как классов исключений, потому что они сами могут выдать исключение во время использования. Если это происходит, то, где Вы будете?

повышение имеет превосходное документ о хорошем стиле для исключений и обработки ошибок. Это стоит чтения.

23
задан Robert Harvey 29 July 2014 в 13:25
поделиться

10 ответов

Вот дружественная памяти функция, которая должна быть способна разбивать большой файл на отдельные запросы без необходимости открывать весь файл сразу :

function SplitSQL($file, $delimiter = ';')
{
    set_time_limit(0);

    if (is_file($file) === true)
    {
        $file = fopen($file, 'r');

        if (is_resource($file) === true)
        {
            $query = array();

            while (feof($file) === false)
            {
                $query[] = fgets($file);

                if (preg_match('~' . preg_quote($delimiter, '~') . '\s*$~iS', end($query)) === 1)
                {
                    $query = trim(implode('', $query));

                    if (mysql_query($query) === false)
                    {
                        echo '<h3>ERROR: ' . $query . '</h3>' . "\n";
                    }

                    else
                    {
                        echo '<h3>SUCCESS: ' . $query . '</h3>' . "\n";
                    }

                    while (ob_get_level() > 0)
                    {
                        ob_end_flush();
                    }

                    flush();
                }

                if (is_string($query) === true)
                {
                    $query = array();
                }
            }

            return fclose($file);
        }
    }

    return false;
}

Я протестировал его на большом SQL дампе phpMyAdmin, и он работал просто отлично.


Некоторые тестовые данные:

CREATE TABLE IF NOT EXISTS "test" (
    "id" INTEGER PRIMARY KEY AUTOINCREMENT,
    "name" TEXT,
    "description" TEXT
);

BEGIN;
    INSERT INTO "test" ("name", "description")
    VALUES (";;;", "something for you mind; body; soul");
COMMIT;

UPDATE "test"
    SET "name" = "; "
    WHERE "id" = 1;

И соответствующий вывод:

SUCCESS: CREATE TABLE IF NOT EXISTS "test" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT, "name" TEXT, "description" TEXT );
SUCCESS: BEGIN;
SUCCESS: INSERT INTO "test" ("name", "description") VALUES (";;;", "something for you mind; body; soul");
SUCCESS: COMMIT;
SUCCESS: UPDATE "test" SET "name" = "; " WHERE "id" = 1;
50
ответ дан 29 November 2019 в 01:18
поделиться

Can you use LOAD DATA INFILE?

If you format your db dump file using SELECT INTO OUTFILE, this should be exactly what you need. No reason to have PHP parse anything.

0
ответ дан 29 November 2019 в 01:18
поделиться

Can't you install phpMyAdmin, gzip the file (which should make it much smaller) and import it using phpMyAdmin?

EDIT: Well, if you can't use phpMyAdmin, you can use the code from phpMyAdmin. I'm not sure about this particular part, but it's generaly nicely structured.

1
ответ дан 29 November 2019 в 01:18
поделиться

Одностраничный PHPMyAdmin - Adminer - всего один файл PHP-скрипта. проверка : http://www.adminer.org/en/

6
ответ дан 29 November 2019 в 01:18
поделиться

что вы думаете по поводу:

system("cat xxx.sql | mysql -l username database"); 
-3
ответ дан 29 November 2019 в 01:18
поделиться

Когда StackOverflow выпустили свой ежемесячный дамп данных в формате XML, я написал PHP-скрипты для загрузки его в базу данных MySQL. Я импортировал около 2.2 гигабайт XML за несколько минут.

Моя техника заключается в том, чтобы подготовить() оператор INSERT с указанием места расположения параметров для значений столбцов. Затем используйте XMLReader для зацикливания XML элементов и execute() моего подготовленного запроса, подключая значения для параметров. Я выбрал XMLReader, потому что это потоковое устройство чтения XML; оно читает входной XML инкрементально, а не требует загрузки всего файла в память.

Вы также можете читать CSV-файл по одной строке за раз с помощью fgetcsv().

Если Вы импортируете в таблицы InnoDB, я рекомендую запускать и фиксировать транзакции явно, чтобы уменьшить накладные расходы на автокомимиссию. Я коммитирую каждые 1000 строк, но это произвольно.

Я не собираюсь публиковать код здесь (из-за лицензионной политики StackOverflow), но в псевдокоде:

connect to database
open data file
PREPARE parameterizes INSERT statement
begin first transaction
loop, reading lines from data file: {
    parse line into individual fields
    EXECUTE prepared query, passing data fields as parameters
    if ++counter % 1000 == 0,
        commit transaction and begin new transaction
}
commit final transaction

Написание этого кода в PHP не является ракетостроением, и он работает довольно быстро, когда используются подготовленные заявления и явные транзакции. Эти возможности недоступны в устаревшем расширении mysql PHP, но вы можете использовать их, если используете mysqli или PDO_MySQL.

Я также добавил такие удобные вещи, как проверка ошибок, отчеты о прогрессе и поддержку значений по умолчанию, когда файл данных не содержит ни одного из полей.

Я написал свой код в PHP-классе абстрактном, который я подклассом для каждой таблицы, которую мне нужно загрузить. Каждый подкласс объявляет столбцы, которые он хочет загрузить, и сопоставляет их с полями в XML файле данных по имени (или по позиции, если файл данных CSV).

.
3
ответ дан 29 November 2019 в 01:18
поделиться
[

]Экспорт[

] [

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

] [
~: mysqldump test --opt --skip-extended-insert | grep -v '^--' | grep . > test.sql
] [

]Это дамп базы данных теста, исключающий все строки комментариев и пустые строки, в test.sql. Также отключает расширенные вставки, означающие, что в каждой строке есть одно утверждение INSERT. Это поможет ограничить использование памяти во время импорта, но со скоростью импорта.[

] [

]Импорт[

] [

]Скрипт импорта так же прост:[

] [
<?php

$mysqli = new mysqli('localhost', 'hobodave', 'p4ssw3rd', 'test');
$handle = fopen('test.sql', 'rb');
if ($handle) {
    while (!feof($handle)) {
        // This assumes you don't have a row that is > 1MB (1000000)
        // which is unlikely given the size of your DB
        // Note that it has a DIRECT effect on your scripts memory
        // usage.
        $buffer = stream_get_line($handle, 1000000, ";\n");
        $mysqli->query($buffer);
    }
}
echo "Peak MB: ",memory_get_peak_usage(true)/1024/1024;
] [

]В этом случае будет задействован абсурдно малый объем памяти, как показано ниже:[

] [
daves-macbookpro:~ hobodave$ du -hs test.sql 
 15M    test.sql
daves-macbookpro:~ hobodave$ time php import.php 
Peak MB: 1.75
real    2m55.619s
user    0m4.998s
sys 0m4.588s
] [

]Это говорит о том, что вы обработали mysqldump размером 15 МБ с пиковым использованием оперативной памяти 1. 75 МБ всего за 3 минуты.[

] [

]Alternate Export[

] [

]Если у вас достаточно большой объем памяти и это слишком медленно, вы можете попробовать это, используя следующий экспорт:[

] [
~: mysqldump test --opt | grep -v '^--' | grep . > test.sql
] [

]Это позволит вставить расширенные вставки, которые вставляют несколько строк в один запрос. Вот статистика для одной и той же базы данных:[

] [
daves-macbookpro:~ hobodave$ du -hs test.sql 
 11M    test.sql
daves-macbookpro:~ hobodave$ time php import.php 
Peak MB: 3.75
real    0m23.878s
user    0m0.110s
sys 0m0.101s
] [

]Обратите внимание, что она использует более 2-х раз больше оперативной памяти при 3.75 Мб, но занимает примерно 1/6 часть времени. Предлагаю попробовать оба метода и посмотреть, какой из них подходит.[

] [

]Правка:[

] [

]Мне не удалось добиться буквального появления новой строки в выводе mysqldump с использованием любого из типов полей CHAR, VARCHAR, BINARY, VARBINARY и BLOB. Если же у вас есть поля BLOB/BINARY, то на всякий случай используйте, пожалуйста, следующее:[

] [
~: mysqldump5 test --hex-blob --opt | grep -v '^--' | grep . > test.sql
]
1
ответ дан 29 November 2019 в 01:18
поделиться

Я столкнулся с той же проблемой. Я решил это с помощью регулярного выражения:

function splitQueryText($query) {
    // the regex needs a trailing semicolon
    $query = trim($query);

    if (substr($query, -1) != ";")
        $query .= ";";

    // i spent 3 days figuring out this line
    preg_match_all("/(?>[^;']|(''|(?>'([^']|\\')*[^\\\]')))+;/ixU", $query, $matches, PREG_SET_ORDER);

    $querySplit = "";

    foreach ($matches as $match) {
        // get rid of the trailing semicolon
        $querySplit[] = substr($match[0], 0, -1);
    }

    return $querySplit;
}

$queryList = splitQueryText($inputText);

foreach ($queryList as $query) {
    $result = mysql_query($query);
}
0
ответ дан 29 November 2019 в 01:18
поделиться

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

-1
ответ дан 29 November 2019 в 01:18
поделиться
Другие вопросы по тегам:

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