Import dużej bazy MySQL przez PHP

Zdjęcie monitora z kodem

W tym wpisie pokażę, jak wczytać ogromny plik .sql do bazy MySQL przy pomocy czystego PHP bez limitów czasu wykonania czy pamięci. To szczególnie przydatne, gdy masz pllik z bazą danych który zajmuje (nawet po spakowaniu do ZIP) więcej niż możesz załadować w phpMyAdmin.

Przygotowanie środowiska PHP

Na początku skryptu zdejmujemy wszystkie standardowe ograniczenia PHP, które przy dużych plikach SQL niemal zawsze powodują problemy:

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
set_time_limit(0);
ini_set('memory_limit', '-1');
ini_set('max_execution_time', 0);
ignore_user_abort(true);

Co tu się dzieje:

  • brak limitu czasu wykonania – import może trwać nawet kilkanaście minut
  • brak limitu pamięci – PHP nie przerwie skryptu przy dużych zapytaniach
  • ignore_user_abort(true) – nawet jeśli zamkniesz kartę w przeglądarce, import będzie trwał dalej
  • pełne raportowanie błędów – przy problemach dokładnie widać, w którym miejscu coś poszło nie tak

Konfiguracja połączenia z bazą danych

W tym miejscu wskazujemy plik SQL oraz dane dostępowe do bazy.

Ważne:

  • plik .sql powinien znajdować się lokalnie na serwerze, nie być uploadowany przez formularz
  • charset=utf8 zapobiega problemom z polskimi znakami
  • każdy błąd SQL zatrzyma skrypt i pokaże czytelny komunikat
  • nie ma „cichych” błędów podczas importu
$sqlFile = __DIR__ . '/baza.sql'; 
$dsn = "mysql:host=localhost;dbname=DBNAME;charset=utf8";
$user = "DBUSER";
$pass = "PASSWORD";
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_LOCAL_INFILE => true
]);

Wyłączenie kluczy obcych przez PDO

$pdo->exec("SET FOREIGN_KEY_CHECKS = 0;");

Dzięki temu:

  • kolejność INSERT i CREATE TABLE nie ma znaczenia
  • unikamy błędów typu Cannot add or update a child row

Po zakończeniu importu klucze zostaną włączone ponownie.

Czytanie pliku SQL linia po linii

Kluczowy fragment skryptu to liniowe czytanie pliku, zamiast ładowania całości do pamięci:

$handle = fopen($sqlFile, "r");
$query = "";

Plik jest czytany przy pomocy fgets(), czyli jedna linia na raz, co pozwala obsłużyć nawet bardzo duże dumpy.

Pomijanie komentarzy i zbędnych instrukcji

Podczas importu ignorujemy:

  • puste linie
  • komentarze SQL
  • CREATE DATABASE
  • USE dbname
if (trim($line) === '' || preg_match('/^(--|#)/', trim($line))) {
continue;
}

if (preg_match('/^\s*CREATE DATABASE/i', $line)) {
continue;
}

if (preg_match('/^\s*USE\s+/i', $line)) {
continue;
}

Składanie i wykonywanie zapytań SQL

Zapytania SQL często zajmują wiele linii. Dlatego linie są sklejane aż do średnika:

$query .= $line;

if (substr(trim($line), -1) === ';') {
$pdo->exec($query);
$query = "";
}

To rozwiązanie:

  • poprawnie obsługuje CREATE TABLE
  • poprawnie obsługuje wielolinijkowe INSERT INTO

Do tego dodajemy obsługę błędów i wyświetlanie postępu.

catch (Exception $e) {
echo "<b>Błąd w linii $lineNumber:</b> " . $e->getMessage();
echo "<pre>$query</pre>";
exit;
}
if ($executed % 100 === 0) {
echo "Wykonano $executed zapytań...<br>";
ob_flush();
flush();
}

Dzięki ob_flush() i flush():

  • przeglądarka odświeża output na żywo
  • widać, że skrypt faktycznie pracuje

Zakończenie importu

fclose($handle);
$pdo->exec("SET FOREIGN_KEY_CHECKS = 1;");
echo "Import zakończony. Wykonano $executed zapytań.";

Podsumowanie

Ten skrypt przydał mi się już kilka razy w praktyce, gdy standardowy import przez phpMyAdmin nie dawał rady — szczególnie przy dużych dumpach baz danych, które przekraczały limity rozmiaru lub czasu wykonania. Dzięki liniowemu czytaniu pliku i zdjęciu ograniczeń PHP import przebiegał stabilnie nawet przy bardzo dużych plikach .sql.

Jeśli masz podobny problem i potrzebujesz prostego, ale skutecznego rozwiązania, ten skrypt powinien spełnić swoje zadanie.

Repozytorium na GitHubie: https://github.com/kamilwyremski/php-mysql-big-importer/

Ta strona używa ciasteczek (cookies), dzięki którym nasz serwis może działać lepiej. Więcej informacji

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close