2016-03-04 15 views
6

Tôi đang cố gắng chèn (trong cơ sở dữ liệu mySQL) từ một tệp CSV "lớn" (3Mo/37000 dòng/7 cột) bằng cách sử dụng các biểu đồ dữ liệu học thuyết.Symfony: Doctrine data fixture: cách xử lý tệp csv lớn?

Quá trình này rất chậm và tại thời điểm này tôi không thể thành công (có thể tôi phải đợi thêm một chút).

Tôi cho rằng đồ thị dữ liệu học thuyết không có ý định quản lý số lượng dữ liệu đó? Có lẽ giải pháp nên được nhập khẩu trực tiếp csv của tôi vào cơ sở dữ liệu?

Bất kỳ ý tưởng nào về cách tiếp tục?

Đây là mã:

<?php 

namespace FBN\GuideBundle\DataFixtures\ORM; 

use Doctrine\Common\DataFixtures\AbstractFixture; 
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; 
use Doctrine\Common\Persistence\ObjectManager; 
use FBN\GuideBundle\Entity\CoordinatesFRCity as CoordFRCity; 

class CoordinatesFRCity extends AbstractFixture implements OrderedFixtureInterface 
{ 
    public function load(ObjectManager $manager) 
    { 
     $csv = fopen(dirname(__FILE__).'/Resources/Coordinates/CoordinatesFRCity.csv', 'r'); 

     $i = 0; 

     while (!feof($csv)) { 
      $line = fgetcsv($csv); 

      $coordinatesfrcity[$i] = new CoordFRCity(); 
      $coordinatesfrcity[$i]->setAreaPre2016($line[0]); 
      $coordinatesfrcity[$i]->setAreaPost2016($line[1]); 
      $coordinatesfrcity[$i]->setDeptNum($line[2]); 
      $coordinatesfrcity[$i]->setDeptName($line[3]); 
      $coordinatesfrcity[$i]->setdistrict($line[4]); 
      $coordinatesfrcity[$i]->setpostCode($line[5]); 
      $coordinatesfrcity[$i]->setCity($line[6]); 

      $manager->persist($coordinatesfrcity[$i]); 

      $this->addReference('coordinatesfrcity-'.$i, $coordinatesfrcity[$i]); 


      $i = $i + 1; 
     } 

     fclose($csv); 

     $manager->flush(); 
    } 

    public function getOrder() 
    { 
     return 1; 
    } 
} 

Trả lời

6

Hai quy tắc để làm theo khi bạn tạo nhập khẩu lô hàng lớn như thế này:

  • Disable SQL Logging: ($manager->getConnection()->getConfiguration()->setSQLLogger(null);) để tránh mất trí nhớ khổng lồ.

  • Xả và xóa thường xuyên thay vì chỉ một lần ở cuối. Tôi đề nghị bạn thêm if ($i % 25 == 0) { $manager->flush(); $manager->clear() } bên trong vòng lặp của bạn, để tuôn ra mỗi 25 INSERT.

EDIT: Một điều cuối cùng tôi quên: không giữ các đối tượng của bạn bên trong biến khi bạn không cần chúng nữa. Ở đây, trong vòng lặp của bạn, bạn chỉ cần thực thể hiện tại đang được xử lý, do đó, không lưu trữ thực thể trước đó trong một mảng $coordinatesfrcity. Điều này có thể dẫn bạn đến tràn bộ nhớ nếu bạn tiếp tục làm điều đó.

+0

Cảm ơn. Tôi đã cố gắng để tuôn ra ở mỗi chèn nhưng nó là một tần số quá quan trọng, tôi giả sử. Tôi sẽ thử đề xuất của bạn. Xin lỗi nhưng SQL Logging là gì? – Cruz

+0

Doctrine đi kèm với một hệ thống ghi nhật ký lưu giữ các dấu vết của các truy vấn SQL được thực thi. Trong bối cảnh này, bạn sẽ không cần nó, và nó sẽ là một chi phí vô dụng của bộ nhớ. – Terenoth

+0

Ok Tôi hiểu đăng nhập SQL là gì. Và bạn nói đúng, bảng này đến từ một đoạn mã khác và không cần thiết ở đây. – Cruz

0

Có một ví dụ tuyệt vời trong Documents: http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/batch-processing.html

Sử dụng một modulo (x% y) biểu thức để thực hiện xử lý hàng loạt, ví dụ này sẽ chèn 20 tại một thời điểm. Bạn có thể tối ưu hóa điều này tùy thuộc vào máy chủ của bạn.

$batchSize = 20; 
for ($i = 1; $i <= 10000; ++$i) { 
    $user = new CmsUser; 
    $user->setStatus('user'); 
    $user->setUsername('user' . $i); 
    $user->setName('Mr.Smith-' . $i); 
    $em->persist($user); 
    if (($i % $batchSize) === 0) { 
     $em->flush(); 
     $em->clear(); // Detaches all objects from Doctrine! 
    } 
} 
$em->flush(); //Persist objects that did not make up an entire batch 
$em->clear(); 
+0

Cảm ơn. Đây là câu trả lời giống Sogara. Tôi sẽ thử nó càng sớm càng tốt. – Cruz

+0

Trên trang tài liệu của tôi ngày hôm trước với một vấn đề tương tự, chỉ nghĩ rằng tôi sẽ cung cấp cho bạn một nguồn như tôi đã có nó để bàn tay. – Sarcoma

+0

Cảm ơn bạn vì điều đó! – Cruz

0

Đối với đồ đạc mà cần rất nhiều bộ nhớ nhưng không phụ thuộc vào nhau, tôi nhận được xung quanh vấn đề này bằng cách sử dụng lá cờ append để chèn một thực thể (hoặc một nhóm nhỏ hơn của thực thể) tại một thời điểm:

bin/console doctrine:fixtures:load --fixtures="memory_hungry_fixture.file" --append 

Sau đó, tôi viết tập lệnh Bash chạy lệnh đó bao nhiêu lần tùy ý.

Trong trường hợp của bạn, bạn có thể mở rộng lệnh Đồ đạc và có cờ thực hiện hàng loạt đối tượng - 1000 hàng đầu tiên, sau đó là 1000 thứ hai, v.v.

Các vấn đề liên quan