Ekstrakcja konkretnych fragmentów z ogromnych zrzutów SQL przy użyciu PHP
Zdarzyło Ci się kiedyś, że musiałeś przywrócić tylko jedną bazę danych lub określoną tabelę z wielogigabajtowego (np. 5 GB) zrzutu MySQL? Otwarcie tak dużego pliku w standardowych edytorach tekstu, takich jak VS Code czy Notepad++, zazwyczaj kończy się drastycznym spadkiem wydajności lub całkowitym zawieszeniem programu.
Zamiast męczyć się z oprogramowaniem desktopowym lub skomplikowanymi narzędziami wiersza poleceń (jak awk czy sed), możemy użyć prostego, wydajnego pod względem pamięci skryptu PHP, aby wyciągnąć dokładnie to, czego potrzebujemy.
Rozwiązanie: Przetwarzanie strumieniowe
Sztuczka polega na tym, aby nie ładować całego pliku do pamięci naraz (co robią funkcje takie jak file_get_contents()). Używając funkcji fgets() w PHP, możemy przetwarzać ogromny plik strumieniowo, linia po linii.
Poniższy skrypt szuka standardowych komentarzy mysqldump, które wskazują początek docelowej bazy danych lub tabeli (np. -- Current Database: db„). Gdy znajdzie nasz cel, przełącza flagę, aby rozpocząć zapisywanie tych linii do nowego pliku. Gdy tylko natrafi na początek innej bazy danych lub tabeli, wyłącza zapis.
Oto kompletny skrypt:
PHP
<?php
ini_set('memory_limit', '2G');
$inputFile = 'dump_5GB.sql';
$outputFile = 'db_fragment.sql';
$targetName = 'db';
$in = fopen($inputFile, 'r');
$out = fopen($outputFile, 'w');
$isExtracting = false;
while (($line = fgets($in)) !== false) {
if (strpos($line, '-- Current Database: `' . $targetName . '`') === 0 ||
strpos($line, 'USE `' . $targetName . '`;') === 0) {
$isExtracting = true;
} elseif (strpos($line, '-- Current Database: `') === 0 ||
strpos($line, 'USE `') === 0) {
$isExtracting = false;
}
if (!$isExtracting) {
if (strpos($line, '-- Table structure for table `' . $targetName . '`') === 0 ||
strpos($line, '-- Table structure for table `' . $targetName . '_') === 0) {
$isExtracting = true;
} elseif (strpos($line, '-- Table structure for table `') === 0) {
$isExtracting = false;
}
}
if ($isExtracting) {
fwrite($out, $line);
}
}
fclose($in);
fclose($out);
Ta metoda utrzymuje zużycie pamięci na ułamkowym poziomie – nie przekraczając kilku megabajtów – i w ciągu kilku sekund przetwarza gigabajty danych SQL.