2012-01-03 24 views
11

Tôi phải cập nhật các thực thể Doctrine của mình để khớp các bản ghi bên trong tệp XML (potentionaly rất lớn). Tôi cũng phải cập nhật các liên kết ManyToMany theo dữ liệu trong XML. Đây là những gì tôi làm trong vòng lặp:doctrine2 - Làm cách nào để cải thiện hiệu quả tuôn ra?

  1. lấy dữ liệu từ XML
  2. get thực thể từ DB (nếu không tồn tại tạo mới)
  3. đặt thuộc tính thực thể mới
  4. được hiệp hội thực hiện (getter trả ArrayCollection đối tượng)
  5. rõ ràng tất cả các hiệp hội (bằng cách gọi ArrayCollection::clear())
  6. thiết lập các hiệp hội mới (bằng cách gọi ArrayCollection::add() trong sub-loop)
  7. tồn tại thực thể bằng cách EntityManager

Sau vòng lặp tôi gọi EntityManager::flush().

Vấn đề là việc xả sẽ tạo ra lượng truy vấn lớn thay vì cập nhật/chèn/xóa nhiều hàng cùng một lúc. Đối với mỗi đơn vị được thực hiện truy vấn sau đây:

  • SELECT để có được tổ chức từ DB
  • UPDATE để cập nhật các thuộc tính thực thể (điều này là thực sự bỏ qua bây giờ như không có tính chất thay đổi ... chưa)
  • DELETE để xóa trước hiệp hội
  • INSERT để chèn các hiệp hội mới

vì vậy, trong tổng số 305 cho các bản ghi trong XML tôi nhận được 915 câu hỏi (tôi đoán nó có thể đi lên đến 1220 truy vấn nếu tất cả các đối tượng sẽ thay đổi) mà làm cho thứ e nhập khẩu rất chậm.

Tôi có thể tận dụng lợi thế của IdentityMap và tìm nạp trước các thực thể trước khi lặp, nhưng vẫn có các truy vấn UPDATE/DELETE/INSERT.

  • Có cách nào để cho phương pháp tuôn ra tối ưu hóa tốt hơn các truy vấn (sử dụng nhiều chèn, WHERE IN thay vì nhiều truy vấn DELETE, v.v ...) không?
  • Đây có phải là hành vi bình thường của phương pháp xả hoặc tôi đang làm điều gì sai?
  • Có thể có vấn đề trong cách tôi cập nhật các liên kết của pháp nhân. Có cách nào tốt hơn làm thế nào để làm điều này? (thay vì "get/clear/add" method)
  • Tôi biết rằng Doctrine không dành cho xử lý betch khối lượng, nhưng tôi nghĩ rằng việc sử dụng nó cho nhập XML là cách tốt nhất để tránh sự không nhất quán của DB có thể xuất hiện với một cách tiếp cận không phải ORM. Có đúng không?
  • Nếu cách tiếp cận trên sai, tôi nên giải quyết vấn đề như thế nào?

Trả lời

30

Bạn đang làm đúng - nó chỉ chậm, bởi vì sự trừu tượng hóa bổ sung của ORM có nghĩa là bạn không thể thực hiện các loại tối ưu bạn muốn.

Điều đó nói rằng, EntityManager không làm chậm các giao dịch lớn.Nếu bạn không hoàn toàn cần tất cả chúng trong một giao dịch lớn, bạn có thể nhận được mã thực hiện nhiều hơn bằng cách flush() ing và sau đó clear() ing EM mỗi 20-200 iterations của vòng lặp của bạn.

Nếu điều đó không giúp bạn có đủ hiệu suất, thay thế duy nhất mà tôi có thể nghĩ là hoàn nguyên về mã tùy chỉnh chạy SQL tùy chỉnh trực tiếp với DBMS của bạn.

Tôi biết đây không phải là câu trả lời tuyệt vời, nhưng ít nhất tôi có thể nói với bạn rằng bạn không điên.

------ chỉnh sửa ------

Từ bài viết chính thức Doctrine2 trên Batch processing:

Một số người dường như tự hỏi tại sao học thuyết không sử dụng đa chèn (chèn vào (...) giá trị (...), (...), (...), ...

Trước hết, cú pháp này chỉ được hỗ trợ trên mysql và mới hơn phiên bản postgresql Thứ hai, không có cách nào dễ dàng để giữ tất cả các số nhận dạng được tạo ra trong một đa chèn như vậy khi sử dụng AUTO_INCREMENT hoặc SERIAL và ORM cần số nhận dạng để nhận dạng số quản lý đối tượng. Cuối cùng, chèn hiệu suất hiếm khi là nút cổ chai của ORM. Chèn bình thường đủ nhanh cho hầu hết các trường hợp và nếu bạn thực sự muốn chèn hàng loạt nhanh, thì một cách chèn nhiều nhất không phải là cách tốt nhất, tức là Postgres COPY hoặc Mysql LOAD DATA INFILE có một số đơn đặt hàng nhanh hơn .

Đây là những lý do tại sao nó không phải là giá trị nỗ lực để thực hiện một sự trừu tượng thực hiện đa chèn trên mysql và postgresql trong một ORM.

Cũng có một sự khác biệt đáng kể trong hoạt động khi sử dụng xa vs cơ sở dữ liệu địa phương như overhead gửi mỗi truy vấn đến máy chủ từ xa là khá lớn. Chi phí thấp hơn nhiều trong khi sử dụng cơ sở dữ liệu cục bộ nhờ các giao dịch và tối ưu hóa DB. (ví dụ: 70 giây được hạ xuống còn 300ms trong trường hợp ví dụ trong câu hỏi)

+5

+1 cho tôi biết rằng tôi không điên :) –

+3

Theo nghiên cứu của tôi không có cách nào để tối ưu hóa tốt hơn việc nhập khi vẫn sử dụng ORM. Tôi đã thêm một số thông tin vào câu trả lời cho các googlers tiềm năng trong tương lai. –

+1

Sau khi thêm $ em-> clear(), sự kiên trì hoạt động nhanh hơn rất nhiều, hoàn toàn giải quyết được vấn đề của tôi. Nếu bạn muốn chèn nhanh hơn, hãy vô hiệu hóa chỉ mục xây dựng lại sau mỗi truy vấn chèn. $ conn-> preparation ('SET autocommit = 0;') -> execute(), và sau khi truy vấn, làm $ conn-> preparation ('COMMIT;') -> execute(); – tomazahlin

3

Không chắc chắn điều này trực tiếp trả lời câu hỏi được đặt ra bởi áp phích gốc hay hy vọng điều này sẽ giúp người khác với các vấn đề về tốc độ của Doctrine khi xả.

... Liên quan đến tốc độ tuôn ra đảm bảo rằng trình định dạng xdebug của bạn chưa được bật.

[php.ini] 
; PROFILING 
;xdebug.profiler_enable = 1 
;xdebug.profiler_output_name = "cachegrind.out.%t.%s.%p" 
;xdebug.profiler_output_dir = "C:\xampp\tmp" 

Ví dụ về mức độ ảnh hưởng của thao tác xả Doctrine trong trường hợp của tôi, 55 giây cho 3000 hồ sơ trong khi trình tắt hồ sơ là 5 giây!

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