2014-10-22 11 views
8

Tôi đang xử lý vấn đề rõ ràng về hiệu suất khi truy xuất ResultSet tương đối lớn từ Microsoft SQL Server 2012 từ xa đến máy khách Java sử dụng Trình điều khiển Microsoft JDBC 4.0.Tại sao truy vấn Microsoft SQL Server 2012 mất vài phút trên JDBC 4.0 nhưng thứ hai (s) trong Management Studio?

Khi tôi chạy truy vấn tương ứng trên Microsoft SQL Server Management Studio của máy chủ từ xa, nó sẽ trả về xấp xỉ. 220k hàng gần như ngay lập tức. Khi tôi phát hành cùng một truy vấn từ máy khách, nó sẽ dừng lại. Các thử nghiệm tương tự đã làm việc tốt cũng trên máy khách với một phiên bản trước đó của cơ sở dữ liệu mà chỉ có khoảng. 400 hàng đủ điều kiện.

Tôi đã cố gắng giải quyết vấn đề này bằng cách thêm ;responseBuffering=adaptive" vào URL được chuyển đến DriverManager.getConnection(). Sau khi kết nối được thiết lập, tôi thấy thuộc tính này (trong số nhiều kết quả khác) trong kết quả từ connection.getMetaData().getURL(), nhưng [connection.getClientInfo(responseBuffering) trả lại null và khách hàng vẫn bị trì hoãn như thế nào.

Điều gì có thể xảy ra ở đây và làm cách nào tôi có thể hướng dẫn một máy chủ Microsoft SQL (không chỉ đề xuất trong Java) mà phải trả về các hàng trong các khối nhỏ hơn là tất cả cùng một lúc hoặc cải thiện thời gian truy vấn JDBC bởi một số biện pháp khác. quan sát

Hai thêm rằng có vẻ hơi kỳ lạ và có lẽ trỏ đến một nguyên nhân gốc rễ khác nhau hoàn toàn:

  • Khi client quầy hàng nó vẫn cho thấy tải CPU chỉ tương đối nhẹ, không giống như những gì tôi mong chờ từ thu gom rác thải nặng
  • "responseBuffering = adaptive" nên là bình thường default bây giờ

CẬP NHẬT tôi đã kiểm tra và thấy rằng việc chuyển đổi từ PreparedStatement đến Statement không cải thiện mọi thứ trong trường hợp của tôi (có vẻ như có thể giúp đỡ trong trường hợp other).

CẬP NHẬT Đây là câu hỏi của tôi hiện tại:

select 
    PARENT.IDENTIFIER as PARENT_IDENTIFIER, 
    PARENT.CLASS   as PARENT_CLASS, 
    CHILD.TYPE   as CHILD_TYPE, 
    CHILD.IDENTIFIER  as CHILD_IDENTIFIER, 
    PROPERTY.IDENTIFIER as PROPERTY_IDENTIFIER, 
    PROPERTY.DESCRIPTION as PROPERTY_DESCRIPTION, 
    PROPERTY.TYPE  as PROPERTY_TYPE, 
    PROPERTY.PP   as PROPERTY_PP, 
    PROPERTY.STATUS  as PROPERTY_STATUS, 
    PROPERTY.TARGET  as PROPERTY_TARGET -- a date 
from 
    OBJECTS as CHILD 
    left outer join RELATIONS    on RELATIONS.CHILD = CHILD.IDENTIFIER 
    left outer join OBJECTS as PARENT on RELATIONS.PARENT = PARENT.IDENTIFIER 
    inner join  PROPERTIES as PROPERTY on PROPERTY.OBJECT = CHILD.IDENTIFIER 
where 
    PROPERTY.TARGET is not null 
order by 
    case when PARENT.IDENTIFIER is null then 1 else 0 end, 
    PARENT.IDENTIFIER, 
    CHILD.IDENTIFIER, 
    PROPERTY.TARGET, 
    PROPERTY.IDENTIFIER 
+1

Bạn có thể sử dụng 'SQLServerStatement' để nhận trạng thái' responseBuffering' thực tế. Xem mã mẫu [ở đây] (http://pastebin.com/zbRPmA2Y). FWIW, mã đó nói với tôi rằng 'adaptive' * là * mặc định với sqljdbc4.jar. –

+0

@GordThompson Tôi bây giờ cũng tin rằng * adaptive * được bật theo mặc định. Mà làm cho hiệu suất rất chậm (theo thứ tự phút cho khách hàng JDBC từ xa so với thứ tự của vài giây trong Microsoft SQL Server Management Studio địa phương tất cả những bí ẩn hơn với tôi. Tại sao một đồng bằng lớn như vậy? – Drux

+1

Bài viết tuyệt vời này ([Làm chậm ứng dụng, nhanh trong SSMS? Hiểu bí quyết về hiệu suất] (http://www.sommarskog.se/query-plan-mysteries.html)) giải thích lý do tại sao –

Trả lời

2

Bộ đệm thích ứng là một câu trả lời hay. Tôi cũng khuyên bạn nên kiểm tra các kết nối 'SET tùy chọn thông qua SQL Server Profiler.

Khi bạn bắt đầu theo dõi, hãy đảm bảo chọn ExistingConnections. So sánh SPID từ kết nối JDBC và kết nối SSMS. ARITHABORT được coi là một trong những điều mà tôi đã thấy gây ra sự khác biệt về hiệu năng giữa trình điều khiển SSMS và JDBC. Microsoft đề cập ngắn gọn ở đây: http://msdn.microsoft.com/en-us/library/ms190306.aspx. Thông tin về Stack Exchange tại đây: https://dba.stackexchange.com/questions/9840/why-would-set-arithabort-on-dramatically-speed-up-a-query

Trên Oracle, tôi đã thấy các tác động lớn bằng cách chơi với phương thức setFetchSize trên đối tượng Statement/PreparedStatement. Rõ ràng, trình điều khiển máy chủ SQL không hỗ trợ phương thức đó. Tuy nhiên, có một phương pháp nội bộ trong trình điều khiển cho nó. Xem Set a default row prefetch in SQL Server using JDBC driver để biết chi tiết.

Ngoài ra, bạn đang làm gì trong vòng lặp while (rs.next()) của mình? Cố gắng không làm gì khác ngoài việc đọc một cột, chẳng hạn như rs.getInt(1). Xem chuyện gì xảy ra. Nếu nó bay, điều đó cho thấy nút cổ chai là trong quá trình xử lý kết quả trước đây của bạn. Nếu nó vẫn còn chậm, thì vấn đề phải ở trong trình điều khiển hoặc cơ sở dữ liệu.

Bạn có thể sử dụng SQL Server Profiler để so sánh các thực thi khi chúng đến qua JDBC và khi bạn chạy nó thông qua SSMS. So sánh CPU, đọc, viết và thời lượng. Nếu chúng khác nhau, thì kế hoạch thực hiện có lẽ khác nhau, điều này chỉ tôi trở lại điều đầu tiên tôi đã đề cập: các tùy chọn SET.

+0

+1 FYI, vấn đề cũng xảy ra dưới dạng 'while (rs.next()) n ++;' Bạn có thể thêm liên kết vào tài liệu về các tùy chọn 'SET', chẳng hạn như' ARITHABORT'. – Drux

+1

Vâng, đã xong. Vì 'while (rs.next())' hiển thị một vấn đề, điều gì sẽ xảy ra nếu bạn thậm chí không làm 'rs.next()'? Chỉ cần thực hiện các tuyên bố và dừng lại ở đó. Chuyện gì xảy ra? Chỉ cố gắng lấy mã đi cho đến khi vấn đề biến mất, hy vọng rằng sẽ tiết lộ nguyên nhân. – Brandon

+0

Không có vòng lặp, nó rất nhanh. Với 'statement.execute (" SET ARITHABORT ON ")' (trả về 'false', BTW) được chèn ngay lập tức sau khi tạo kết nối và trước vòng lặp, nó vẫn còn rất (phút) chậm. – Drux

0

Có lẽ, liên kết này từ tài liệu Microsoft có thể giúp bạn giải quyết vấn đề của bạn: http://msdn.microsoft.com/en-us/library/bb879937(v=sql.110).aspx

Đặc biệt trong "Hướng dẫn sử dụng adaptive đệm "một phần:

Có một số trường hợp sử dụng SelectMethod = con trỏ thay vì responseBuffering = adaptive sẽ có lợi hơn, chẳng hạn như:

Nếu ứng dụng của bạn xử lý một chuyển tiếp chỉ, chỉ đọc kết quả thiết lập chậm, chẳng hạn như đọc mỗi hàng sau khi một số người dùng nhập vào, sử dụng selectMethod = cursor thay vì responseBuffering = adaptive có thể giúp giảm mức sử dụng tài nguyên của SQL Server.

Nếu ứng dụng của bạn xử lý hai hoặc nhiều chuyển tiếp chỉ, read-only dẫn bộ cùng lúc trên cùng một kết nối, sử dụng SelectMethod = con trỏ thay vì responseBuffering = adaptive có thể giúp làm giảm bộ nhớ yêu cầu của trình điều khiển trong khi xử lý các tập hợp kết quả này.

Trong cả hai trường hợp, bạn cần xem xét chi phí tạo, đọc và đóng con trỏ máy chủ.

+0

Thx, nhưng tài liệu này đã được liên kết trong câu hỏi, vì vậy tiếc là không có sự trợ giúp rõ ràng ở đó. – Drux

2

Tôi chỉ đơn giản là sẽ tung ra đề xuất này và để nó cho bạn thử nghiệm.

Trình điều khiển JDBC cũng có thể BẬT tất cả các hàng trước khi nó trả về, trong khi hệ thống khác chỉ đơn giản là trả lại con trỏ mở.

Tôi đã thấy hành vi này trên các cơ sở dữ liệu khác với JDBC, nhưng không có kinh nghiệm trực tiếp với SQL Server.

Trong các ví dụ mà tôi đã thấy, hãy đặt cam kết tự động thành sai cho kết nối ngăn không cho tải toàn bộ tập kết quả. Có các cài đặt khác để cài đặt chỉ tải các phần, v.v.

Nhưng đó cũng có thể là vấn đề cơ bản mà bạn đang gặp phải.

+1

+1 nhưng không may thiết lập tự động cam kết sai có vẻ không tạo nên sự khác biệt trong trường hợp này. – Drux

2

Chúng tôi gặp phải sự cố tương tự đã xảy ra do bộ nhớ đệm. Chúng tôi đã tham khảo một bài đọc rất hay về query plans.

SQL Server kế hoạch lưu trữ thực hiện, bạn có thể nhìn thấy nó sử dụng:

select * from sys.dm_exec_cached_plans 

gì làm việc cho chúng tôi đã bỏ qua kế hoạch thực hiện lưu trữ cho các truy vấn chậm.

Điều gì xảy ra có thể là do các truy vấn khác nhau, giai đoạn tối ưu hóa sẽ tính đến các giá trị tham số của truy vấn. Vì trong một số trường hợp, nó có ý nghĩa hơn khi sử dụng một kế hoạch thực thi khác.

Nếu kế hoạch thực hiện đã được lưu trong bộ nhớ cache và có một lần truy cập bộ nhớ cache (sử dụng câu lệnh đã chuẩn bị, bỏ qua tham số), kế hoạch thực hiện có thể tối ưu cho cùng truy vấn với các tham số khác nhau.

Để xác minh điều này, bạn có thể thử và khôi phục một số truy vấn và xem liệu bạn có nhận được một kế hoạch thực hiện khác cho cùng một truy vấn với thông số khác không.

Nếu đó hóa ra là như vậy, có một số điều bạn có thể làm:

  • Đối với một kết quả ngay lập tức thêm một biên dịch lại gợi ý OPTION (RECOMPILE) để truy vấn của bạn. Điều này sẽ biên dịch lại truy vấn mỗi lần nhưng có thể nhanh hơn rất nhiều so với những gì bạn đang có. Từ các tài liệu:

biên dịch lại - Chỉ định SQL Server Database Engine để loại bỏ các kế hoạch tạo ra cho các truy vấn sau khi nó thực thi, buộc các truy vấn tối ưu để biên dịch lại một kế hoạch truy vấn trong thời gian tới cùng một truy vấn được thực thi. Nếu không chỉ định RECOMPILE, Database Engine sẽ lưu trữ các kế hoạch truy vấn và tái sử dụng chúng. Khi biên dịch các kế hoạch truy vấn, gợi ý truy vấn RECOMPILE sử dụng các giá trị hiện tại của bất kỳ biến cục bộ nào trong truy vấn và, nếu truy vấn nằm trong thủ tục được lưu trữ, các giá trị hiện tại được truyền cho bất kỳ tham số nào.

  • Bộ nhớ cache không hợp lệ (xem Recompiling Execution Plans). Các cách để làm mất hiệu lực bộ nhớ cache là. Lưu ý: một số trong những không được hỗ trợ trong xanh:
  1. Thay đổi thực hiện cho một bảng hoặc view tham chiếu bởi các truy vấn (ALTER TABLE và ALTER VIEW).

  2. Các thay đổi được thực hiện cho một quy trình, sẽ làm giảm tất cả kế hoạch cho quy trình đó từ bộ nhớ cache (ALTER PROCEDURE).

  3. Thay đổi đối với bất kỳ chỉ mục nào được sử dụng bởi gói thực hiện.

  4. Cập nhật về thống kê được kế hoạch thực hiện sử dụng, được tạo rõ ràng từ tuyên bố, chẳng hạn như CẬP NHẬT CẬP NHẬT, hoặc được tạo tự động.

  5. Thả chỉ mục được sử dụng bởi gói thực hiện.

  6. Cuộc gọi rõ ràng để sp_recompile.

  7. Số lượng lớn thay đổi đối với khóa (được tạo bởi INSERT hoặc DELETE câu lệnh từ những người dùng khác sửa đổi bảng được tham chiếu bởi truy vấn).

  8. Đối với các bảng có trình kích hoạt, nếu số hàng trong các bảng được chèn hoặc bị xóa sẽ tăng đáng kể.

  9. Thực hiện quy trình được lưu bằng cách sử dụng tùy chọn WITH RECOMPILE.

  • Tối ưu hóa kế hoạch bằng tay sử dụng OPTIMIZE FOR gợi ý (không thử nó).

  • Sử dụng truy vấn riêng sau khi phân loại thông số.

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