2012-11-15 42 views
5

Tôi có các thực thể JPA Đặt hàng có quan hệ ManyToOne với Khách hàng. Nó là hai chiều, để khách hàng cũng có một đơn đặt hàng trường OneToMany. Cả hai quan hệ này đều sử dụng hàm EAGER (hoặc nằm trong vùng tìm nạp OpenJPA).ngăn N + 1 chọn trong JPA

Khi tôi chọn từ Đơn đặt hàng, tôi nhận được 1 lựa chọn cho các đơn hàng và N chọn cho trường Customer.orders. Để tôi ngạc nhiên vấn đề này là hiện tại với OpenJPA, EclipseLink và Hibernate, ngay cả khi tôi sử dụng JOIN FETCH (mà không làm việc trong một trường hợp một chiều).

Có cách nào tốt để giải quyết vấn đề này không? Có giải pháp nào để giải quyết vấn đề chọn N + 1 cho các đồ thị phức tạp hơn không?

EDIT: Kết quả nghiên cứu của riêng tôi: - Đối với OpenJPA (tôi đang sử dụng) Tôi chưa biết giải pháp nào - Đối với Hibernate @Fetch (FetchMode.SUBSELECT) giải quyết vấn đề. Sử dụng @BatchSize cũng giúp, điều này chọn một số lượng nhất định của các trường customer.orders cùng một lúc. - Đối với EclipseLink tôi tìm thấy một tính năng tương tự @BatchFetch (value = BatchFetchType.IN) nhưng nó không giúp ích trong trường hợp này, tôi cho rằng nó không thể xử lý hiệu quả điều này trong một mối quan hệ hai chiều.

+0

Đây có lẽ là một câu hỏi rambly. Bạn có * một vấn đề cụ thể * bạn muốn trợ giúp hoặc bạn chỉ muốn khiếu nại về JPA? – millimoose

+0

Bạn nói đúng, tôi cảm thấy hơi thất vọng với JPA, tôi sẽ chỉnh sửa câu hỏi của mình để trở nên quan trọng hơn. –

+1

Bạn có thực sự cần tìm nạp EAGER trên Customer.orders không? – Esteve

Trả lời

-1

Trong bất kỳ khung ORM nào, vấn đề N + 1 là phổ biến. Bạn không thể tránh điều đó. Tuy nhiên, đây là nhiều hơn về cách tiếp cận kinda bạn thực hiện để giải quyết vấn đề. Bạn có thể sử dụng các liên kết và tải chậm hoặc ngày tải mong muốn dựa trên việc triển khai của bạn. Bạn cũng có thể thực hiện ánh xạ cơ sở dữ liệu và getc tất cả dữ liệu được liên kết trong một truy vấn và bạn có thể ánh xạ nó vào Mô hình của bạn. Vì cơ sở dữ liệu được lập chỉ mục, thao tác này có thể nhanh hơn bạn tìm nạp dữ liệu và ánh xạ bằng các truy vấn N + 1 (Nếu độ trễ mạng của bạn cho phép).

1

Hãy xem: What is SELECT N+1? vì có rất nhiều thông tin tốt ở đó.

Nếu bạn sử dụng Hibernate: Hibernate - Chapter 19: Improving Performance - Fetching Strategies

My own personal solution is to use native SQL and tmp ids table đó là bởi vì thường IMHO N + 1 chọn vấn đề chủ yếu là một vấn đề với xử lý hàng loạt. Nếu không, tải chậm (thường là giải pháp N + 1) có thể mang lại lợi ích cho hiệu suất.

+1

Cảm ơn bạn, bằng cách sử dụng truy vấn gốc chắc chắn có thể hữu ích. Nhưng điều này cảm thấy như bạn phải viết tay cái gì đó phải là trách nhiệm của ORM để thực hiện. Điều này có thể dẫn đến rất nhiều công việc thủ công và một cơn ác mộng bảo trì. –

+0

@SlowStrider Ý tưởng là bạn không cần phải làm điều này rất thường xuyên. Tải xuống lười biếng N + 1 thường là cách phù hợp cho hầu hết các sự cố. Bên cạnh đó khi nói đến hiệu suất tối ưu hóa đáng tin cậy như thế này bạn sẽ thấy rằng SQL (không JPA HQL) là lựa chọn duy nhất của bạn ... do đó, không làm điều đó, trừ khi bạn phải. –

+0

Đối với các cử tri xuống nó sẽ giúp nếu bạn có thể xin vui lòng cho tôi biết lý do tại sao. Vấn đề chọn N + 1 không thể sửa được một cách kỳ diệu. Bạn hoặc có một sản phẩm Descartes của các lĩnh vực hoặc bạn lười biếng tải từng đối tượng. Tôi không chắc những gì mọi người đang mong đợi. Không có ORM chết tiệt nào có thể dự đoán hiệu năng cơ sở dữ liệu và quyết định ngẫu nhiên khi nào làm háo hức (sản phẩm Descartes) và lười biếng (N + 1). Tôi không chắc những gì mọi người đang mong đợi. Tôi xin lỗi tôi không thể chỉ cung cấp một mã cut'n dán để làm cho vấn đề này biến mất. –

0

Đây là một giải pháp:

  1. riêng các lớp thực thể từ lớp API và tương tác với các trường hợp API duy nhất bên trong bạn ứng dụng. Api trong ngữ cảnh này cũng có thể được gọi là DTO.

  2. Xóa mối quan hệ hoàn toàn khỏi Thực thể.

  3. Tạo cơ chế để cho biết bạn muốn tìm nạp trẻ em. Ví dụ: tuyên truyền fetchRequestList cho lớp ánh xạ API tới thực thể (theo cách đó bạn có thể tìm nạp theo điều kiện).

  4. Trong khi thực hiện truy vấn thu thập các đối tượng cha mẹ như bình thường.

  5. Truy lục toàn bộ bộ sưu tập của trẻ bằng cách sử dụng truy vấn được tham số được đặt tên có mệnh đề IN dựa trên FK đến PK mẹ.

  6. Lặp lại các kết quả và khớp chúng với bố mẹ.

Điều này sẽ buộc ORM thực hiện truy vấn n + 1 thay vì truy vấn n (n + 1).Hãy nhớ rằng bây giờ bạn sẽ phải thực hiện thác, lưu, xóa, cập nhật, vv bằng cách sử dụng logic tùy chỉnh.

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