2012-02-26 29 views
18

Tôi vừa thử nghiệm ứng dụng của mình theo profiler và phát hiện ra rằng chuỗi sql sử dụng khoảng 30% bộ nhớ của tôi! Đây là kỳ quái.Hibernate tạo ra các SQL khác nhau cho mỗi truy vấn

Có rất nhiều chuỗi như thế này được lưu trữ trong bộ nhớ ứng dụng. Đây là các truy vấn SQL được tạo bởi hibernate, lưu ý các số khác nhau và dấu gạch dưới sau:

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=? for update 
select avatardata0_.Id as Id4347_0_,...... where avatardata0_.Id=? for update 

Đây là phần tôi không thể hiểu được. Tại sao hibernate phải tạo các chuỗi sql khác nhau với các số nhận dạng khác nhau như "Id4305_0_" cho mỗi truy vấn? Tại sao nó không thể sử dụng một chuỗi truy vấn cho tất cả các truy vấn giống nhau? Đây có phải là một số loại lừa để bỏ qua truy vấn bộ nhớ đệm?

Tôi sẽ đánh giá rất cao nếu ai đó mô tả cho tôi lý do tại sao điều đó xảy ra và cách tránh lãng phí tài nguyên đó.

CẬP NHẬT

Ok. Tôi tìm thấy nó. Tôi đã sai giả định rò rỉ bộ nhớ, Đó là lỗi của tôi. Hibernate đang hoạt động như dự định.

Ứng dụng của tôi đã tạo 121 (!) SessionFactories trong 10 chủ đề, chúng tạo ra khoảng 2300 bản sao của SingleTableEntityPersisters. Và mỗi SingleTableEntityPersister tạo ra khoảng 15 truy vấn SQL với các định danh khác nhau. Hibernate đã buộc phải tạo ra khoảng 345.000 truy vấn SQL khác nhau. Mọi thứ đều ổn, không có gì lạ :)

+1

Nó có thể hữu ích nếu bạn có thể cung cấp một cấu hình bản đồ đơn giản, mã kiểm tra và DDL bảng đơn giản mà tái tạo tình trạng này. Theo kinh nghiệm của tôi, tôi chưa bao giờ thấy Hibernate tạo ra chỉ số bí danh cột cao như vậy. –

+0

Điểm tốt. Tôi sẽ thử vào ngày mai. :) –

+0

@AndrewFrolov: Hy vọng câu trả lời của tôi phù hợp với câu hỏi tốt hơn ngay bây giờ, với các cập nhật của bạn.Trong mọi trường hợp vui mừng bạn đã tìm thấy và khắc phục vấn đề! – ManuPK

Trả lời

1

Có một logic đằng sau chuỗi truy vấn tạo ngủ đông. Mục đích chính của nó là để nhận được bí danh duy nhất cho tên bảng và cột.

Từ truy vấn của bạn,

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=?

avatardata0_ ==>avatardata là bí danh của bảng và 0_ được nối để chỉ ra đó là bảng đầu tiên trong truy vấn. Vì vậy, nếu đó là bảng thứ hai (hoặc thực thể) trong truy vấn, nó phải được hiển thị là avatardata1_. Nó sử dụng cùng một logic cho các bí danh cột.

Vì vậy, theo cách này, tất cả các xung đột có thể tránh được.

Bạn đang nhìn thấy các truy vấn này vì bạn đã bật cấu hình show_sql gắn cờ cấu hình. Điều này nhằm mục đích gỡ lỗi truy vấn. Khi ứng dụng của bạn bắt đầu hoạt động, bạn phải tắt nó đi.

Đọc thêm về tài liệu API here.

Tôi không biết nhiều về phần tiêu thụ bộ nhớ, nhưng bạn lặp lại các thử nghiệm của mình với cờ phía trên bị tắt và xem có cải thiện nào không.

+1

show_sql bị tắt. Tôi không nói về nhật ký, tôi đang nói về trí nhớ. Tôi thấy các truy vấn này trong hồ sơ, trong bộ nhớ ứng dụng, có thể là trong bộ nhớ cache hibernate nội bộ. Tôi hiểu tại sao hibernate tạo một bí danh cho mỗi cột trong một tập hợp kết quả. Tôi không hiểu tại sao hibernate không thể tái sử dụng câu lệnh được tạo cho truy vấn tiếp theo. –

+0

OK. Tôi đã trả lời về ** tại sao tên dài ** một phần? Thậm chí tôi không chắc chắn về giải pháp! – ManuPK

+0

Bạn có tài liệu nào giải thích tại sao không * tại sao * họ làm điều này? Nó có thể gây ra vấn đề hiệu suất vào những thời điểm ... http://stackoverflow.com/a/15257317/32453 – rogerdpack

1

Giả sử bạn đang sử dụng máy chủ sql, bạn có thể muốn kiểm tra khai báo kiểu tham số cho '?', Đảm bảo khai báo kết quả trong cùng một khai báo chiều dài cố định mỗi lần.

Tham số chiều dài động sẽ dẫn đến các kế hoạch thực hiện riêng biệt cho mỗi truy vấn. Điều này có thể có thể comsume rất nhiều tài nguyên.Những gì chúng ta thấy là thủ tục tương tự, nhận được giải thích bởi máy chủ sql như một truy vấn khác, kết xuất một kế hoạch thực hiện riêng biệt.

Như vậy,

exec myprocedure @p1 varchar(3)='foo' 

exec myprocedure @p1 varchar(6)='foobar' 

sẽ cho kết quả trong kế hoạch khác nhau. Đơn giản chỉ cần thực tế là các khai báo của @ p1, có kích thước khác nhau.

Có rất nhiều điều cần biết về hành vi này. Nếu những điều trên áp dụng cho bạn, tôi khuyên bạn nên đọc về 'tham số sniffing'.

-1

Không ... bạn có thể tạo cho bạn truy vấn chung bên trong chế độ ngủ đông. Logic đằng sau là lập bản đồ với bảng và tìm nạp bản ghi từ đó. Nó được sử dụng phổ biến truy vấn cho tất cả các cơ sở dữ liệu. Hãy tạo một truy vấn phổ biến như thế:

Ví dụ:

select t.Id as Id4305_0_,...... from t where t.Id=? 
Các vấn đề liên quan