Autor Wątek: Doctrine wydajność  (Przeczytany 3267 razy)

nicraM

  • Newbie
  • *
  • Wiadomości: 43
    • Zobacz profil
Doctrine wydajność
« dnia: Styczeń 22, 2018, 17:54:21 »
Witam
Piszę małą apkę, która musi korzystać z terytowej bazy danych http://eteryt.stat.gov.pl/eTeryt/rejestr_teryt/udostepnianie_danych/baza_teryt/uzytkownicy_indywidualni/pobieranie/pliki_pelne_struktury.aspx.
Na razie mam taki draft parsera:
protected function updateDatabase(SymfonyStyle $io, ProgressBar $bar)
{
$f = $this->terytDir . DIRECTORY_SEPARATOR . 'TERC.xml';

$bar->setMessage('Preparing to update DB Setting "Polska" as Country', 'status');
$bar->advance(1000);
$bar->advance(-1000);

$polska = $this->entityManager->getRepository(LocationCountry::class)->findOneByName('Polska');
if ($polska) {
$this->country = $polska;
} else {
$this->country = new LocationCountry();
$this->country->setName('Polska');
$this->entityManager->persist($this->country);
$this->entityManager->flush();
}

// Setting RODZ, RODZ_X from documentation on GUS pages
// http://eteryt.stat.gov.pl/eTeryt/rejestr_teryt/udostepnianie_danych/baza_teryt/uzytkownicy_indywidualni/pobieranie/pliki_pelne_struktury.aspx
$typeRepo = $this->entityManager->getRepository(LocationBoroughsType::class);
$stateRepo = $this->entityManager->getRepository(LocationState::class);
$districtRepo = $this->entityManager->getRepository(LocationDistrict::class);
$boroughRepo = $this->entityManager->getRepository(LocationBorough::class);
$boroughsTypeRepo = $this->entityManager->getRepository(LocationBoroughsType::class);

$types = [
'1' => 'gmina miejska',
'2' => 'gmina wiejska',
'3' => 'gmina miejsko-wiejska',
'4' => 'miasto w gminie miejsko-wiejskiej',
'5' => 'obszar wiejski w gminie miejsko-wiejskiej',
'8' => 'dzielnica w m.st. Warszawa',
'9' => 'delegatury miast: Kraków, Łódź, Poznań i Wrocław'
];

$bar->setMessage('Updateing Location Boroughs types', 'status');
foreach ($types as $k => $name){
$bar->advance();
if ($typeDb = $typeRepo->findOneBy(['idTeryt' => $k])){
if($typeDb->getName() === $name) {
continue;
} else {
$typeDb->setName($name);
}

} else {
$type = new LocationBoroughsType();
$type->setIdTeryt($k);
$type->setName($name);
$this->entityManager->persist($type);
}
}
$this->entityManager->flush();

foreach ($types as $k => $t) {
$this->boroughsTypes[$k] = $boroughsTypeRepo->findOneBy(['idTeryt' => $k]);
}


$data = [];

$xml = simplexml_load_file($f);

$bar->setMessage('Przetwarzam TERC', 'status');
$idx = 0;



foreach ($xml->catalog->row as $row) {

// if ($idx === 5) {
// break;
// }

// jeśli jest Województwo sprawdzamy dalej
if ($row->POW != ''){
if ($this->state->getIdent() != $row->WOJ) {
$this->state = $stateRepo->findOneBy(['ident' => $row->WOJ]);
}

// Sprawdzamy czy jest ustawiony powiat. Jeśli GMI brak to znaczy, że jest to powiat
if ($row->GMI != ''){
if ($this->state->getIdent() != $row->WOJ && $this->district != $row->POW){
$this->district = $districtRepo->findOneBy(['ident' => $row->POW, 'state' => $this->state]);
}
// jeśli gmina istnieje to zrobimy update
if ($borough = $boroughRepo->findOneBy(['ident' => $row->GMI, 'district' => $this->district])) {
//
} else { // Jeśli gminy nie ma to dodamy

$borough = new LocationBorough();
$borough->setIdent($row->GMI);
$borough->setDistrict($this->district);
$borough->setName($row->NAZWA);
if ($row->RODZ->__toString() !== null ) {
$borough->setType($this->boroughsTypes[$row->RODZ->__toString()]);
}
$this->entityManager->persist($borough);
}
$this->entityManager->flush();
} else { // nie ma powiatu to go dodamy

$bar->setMessage('Setting district: ' . $row->NAZWA.' ident: '.$row->POW.' state: '.$this->state->getName(), 'status');
$bar->advance(1000);
$bar->advance(-1000);

if (!$this->state->getIdent() != $row->WOJ){
$this->state = $stateRepo->findOneBy(['ident' => $row->WOJ]);
}

// Sprawdzamy, czy już taki istnieje. Jeśli tak, to go updateujemy

if ($district = $districtRepo->findOneBy(['ident' => $row->POW, 'state' => $this->state]))
{
$district->setName($row->NAZWA);
$district->setState($this->state);

} else {
$district = new LocationDistrict();
$district->setIdent($row->POW);
$district->setName($row->NAZWA);
$district->setState($this->state);
$this->entityManager->persist($district);

}

$this->entityManager->flush();
$this->district = $district;

$bar->advance(1000);
$bar->advance(-1000);
}
}
else { // nie ma województwa więc je dodamy
$bar->setMessage('Setting state: ' . $row->NAZWA, 'module');

if ($state = $stateRepo->findOneBy(['ident' => $row->WOJ])) {
if ($state->getName() !== $row->NAZWA){
$state->setName($row->NAZWA);
$this->entityManager->flush();
}
} else {
$state = new LocationState();
$state->setCountry($this->country);
$state->setIdent($row->WOJ);
$state->setName($row->NAZWA);
$this->entityManager->persist($state);
$this->entityManager->flush();
}
// ustawiam powiat by w pętli nie wykonwyać ciągle selectów
$this->state = $state;

$bar->advance(1000);
$bar->advance(-1000);
}
$bar->advance();
$idx++;
}

$data['STAN_NA'] = $xml->catalog['date'];

$bar->setMessage('SIMC Teryt DONE', 'status');
);
return true;

}
Parsowanie i wrzucanie do DB trochę trwa :/ nie wiem czy nie dałoby się tego jakoś wydajniej zrobić.
Jak z flushowaniem danych? czy lepiej zrobić co insert flush czy może tak jak jest tu w kodzie robić partiami?

Valantir

  • Hero Member
  • *****
  • Wiadomości: 574
    • Zobacz profil
Odp: Doctrine wydajność
« Odpowiedź #1 dnia: Styczeń 23, 2018, 13:58:05 »
Ja zawsze robiłem po około 100 rekordów.

Tutaj przykład:
https://stackoverflow.com/questions/18654530/doctrine2-multiple-insert-in-one-shot

Na czas importu możesz wyłączyć logowanie zapytań:

$manager->getConnection()->getConfiguration()->setSQLLogger(null);