2011-08-03 12 views
8

im posiadające bardzo kłopotliwe czas próby importowania dużego pliku csv do mysql na localhostImportowanie dużą csv do bazy danych mysql

CSV wynosi około 55 MB i ma około 750 tysięcy wierszy.

teraz ive uciekają się do napisania skryptu, który analizuje csv i składowisk wiersze 1 przez jeden

heres kodu:

$row = 1; 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 

      $postcode = mysql_real_escape_string($arr[1]); 
      $city_name = mysql_real_escape_string($arr[2]); 
      $city_slug = mysql_real_escape_string(toAscii($city_name)); 
      $prov_name = mysql_real_escape_string($arr[3]); 
      $prov_slug = mysql_real_escape_string(toAscii($prov_name)); 
      $prov_abbr = mysql_real_escape_string($arr[4]); 
      $lat = mysql_real_escape_string($arr[6]); 
      $lng = mysql_real_escape_string($arr[7]); 

      mysql_query("insert into cities (`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
         values ('$postcode', '$city_name', '$city_slug', '$prov_name', '$prov_slug', '$prov_abbr', '$lat', '$lng')") or die(mysql_error()); 
     } 
    } 
    fclose($handle); 
} 

problem jest ten trwa na wieki, aby wykonać ... wszelkie rozwiązania byłoby wspaniale.

+0

Czy masz wskaźniki na stole? Jeśli tak, rozważ wstawianie indeksów wyłączonych i odbudowujących po zakończeniu. –

+0

"Plik danych obciążenia mysql" może obsłużyć większość formatów CSV bezpośrednio: http://dev.mysql.com/doc/refman/5.1/en/load-data.html (szukaj "csv"). –

Odpowiedz

6

Jesteś wyważania otwartych drzwi. Sprawdź narzędzie mysqlimport dostarczane z MySQL. Jest to wydajne narzędzie do importowania plików danych CSV.

mysqlimport to interfejs wiersza poleceń dla instrukcji SQL LOAD DATA LOCAL INFILE.

Powinno działać 10-20 razy szybciej niż wykonywanie INSERT po rzędzie.

+0

próbowałem tego, ale jest przepełniony błędem po błędzie. – scarhand

+2

W końcu zorientowałem się, używając tego przewodnika: http://vegdave.wordpress.com/2007/05/19/import-a-csv-file-to-mysql-via-phpmyadmin/ – scarhand

+0

Dzięki narzędziu 'mysqlimport' CLI pracował dla mnie! –

2

Twój problem prawdopodobnie polega na tym, że masz automatyczne zatwierdzanie (domyślnie), więc MySQL zatwierdza nową transakcję dla każdej wstawki. Powinieneś wyłączyć autocommit na SET autocommit=0;. Jeśli możesz przełączyć się do korzystania z biblioteki mysqli (i powinieneś, jeśli to możliwe), możesz użyć mysqli::autocommit(false), aby wyłączyć autocommitting.

$mysqli = new mysqli('localhost','db_user','my_password','mysql'); 
$mysqli->autocommit(false); 
$stmt=$mysqli->prepare("insert into cities (`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
        values (?, ?, ?, ?, ?, ?, ?, ?);") 


$row = 1; 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 
      $stmt->bind_param('ssssssdd', $arr[1], $arr[2], toAscii(arr[2]), $arr[3], toAscii($arr[3]), $arr[4], $arr[6], $arr[7]); 
      $stmt->execute(); 
     } 
    } 
} 
$mysqli->commit(); 
fclose($handle); 
1

Spróbuj zrobić to w jednym zapytaniu.

To może być ograniczona przez my.cnf (konfiguracja mysql), choć

<?php 

$row = 1; 
$query = ("insert into cities "); 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 

      $postcode = mysql_real_escape_string($arr[1]); 
      $city_name = mysql_real_escape_string($arr[2]); 
      $city_slug = mysql_real_escape_string(toAscii($city_name)); 
      $prov_name = mysql_real_escape_string($arr[3]); 
      $prov_slug = mysql_real_escape_string(toAscii($prov_name)); 
      $prov_abbr = mysql_real_escape_string($arr[4]); 
      $lat = mysql_real_escape_string($arr[6]); 
      $lng = mysql_real_escape_string($arr[7]); 
      $query .= "(`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
         values ('$postcode', '$city_name', '$city_slug', '$prov_name', '$prov_slug', '$prov_abbr', '$lat', '$lng'),"; 

     } 
    } 
    fclose($handle); 
} 
mysql_query(rtrim($query, ",")); 

jeśli to nie zadziała, możesz spróbować (wyłączyć automatyczny zobowiązać)

mysql_query("SET autocommit = 0"); 
$row = 1; 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 

      $postcode = mysql_real_escape_string($arr[1]); 
      $city_name = mysql_real_escape_string($arr[2]); 
      $city_slug = mysql_real_escape_string(toAscii($city_name)); 
      $prov_name = mysql_real_escape_string($arr[3]); 
      $prov_slug = mysql_real_escape_string(toAscii($prov_name)); 
      $prov_abbr = mysql_real_escape_string($arr[4]); 
      $lat = mysql_real_escape_string($arr[6]); 
      $lng = mysql_real_escape_string($arr[7]); 

      mysql_query("insert into cities (`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
         values ('$postcode', '$city_name', '$city_slug', '$prov_name', '$prov_slug', '$prov_abbr', '$lat', '$lng')") or die(mysql_error()); 
     } 
    } 
    fclose($handle); 
} 
+0

wstawienie za pomocą jednego zapytania rzucił "Ostrzeżenie: błąd podczas wysyłania pakietu QUERY. PID = 1260" – scarhand

+0

@scarhand: Powiedziałem, że może to spowodować błąd w jednym zapytaniu ... – genesis

1

zrobiłem to z serwerem SQL:

  • Użyłem polecenia SQL Bulkinsert w połączeniu z tabelami danych.
  • Tabele danych znajdują się w pamięci i są zbudowane na podstawie odczytów wierszy znajdujących się w pliku.
  • Każda tabela danych jest zbudowana z kawałka wierszy, a nie z całego pliku.
  • Śledzenie porcji przetworzonej przez zachowanie wskaźników z ostatniego wiersza odczytu i maksymalnego rozmiaru porcji.
  • Podczas czytania pliku. wyjdź z pętli, gdy id rzędu> ostatni wiersz + rozmiar porcji.
  • Utrzymywanie pętli i kontynuowanie wkładania.
2

To będzie o wiele szybsze w użyciu LOAD DATA jeśli można

0

Czasami, gdy używasz Dane obciążenia, jeśli istnieją ostrzeżenia, import zostanie zatrzymany. Możesz użyć słowa kluczowego ignoruj.

LOAD DATA INFILE 'file Path' IGNORE INTO TABLE YOUR_Table 
0

miałem podobną sytuację gdzie jest to możliwe, aby nie było wykorzystać dane LOAD. Transakcje były również nie do przyjęcia, ponieważ dane musiały być sprawdzane pod kątem duplikatów.Jednak poniższe radykalnie poprawiły czas przetwarzania niektórych moich plików danych importu.

Przed pętla while (CSV Lines) ustawić trybu automatycznego na 0 i rozpocząć transakcję (tylko InnoDB):

mysql_query('SET autocommit=0;'); 
mysql_query('START TRANSACTION;'); 

Po pętla, popełnić i zresetować AUTOCOMMIT z powrotem do 1 (domyślnie):

mysql_query('COMMIT;'); 
mysql_query('SET autocommit=1;'); 

Zamień mysql_query() na dowolny obiekt bazy danych, z którego korzysta twój kod. Mam nadzieję, że to pomoże innym.