Chúng tôi đang sử dụng SQL Server 2008 R2 và có một bảng rất lớn (100M + hàng) với chỉ mục id chính và một datetime
cột có chỉ mục không bao gồm. Chúng tôi đang thấy một số hành vi máy khách / máy chủ rất bất thường dựa trên việc sử dụng một order by
mệnh đề cụ thể trên cột datetime được lập chỉ mục .
Tôi đã đọc qua bài viết sau: /programming/1716798/sql-server-2008-ordering-by-datetime-is-too-slow nhưng có nhiều điều xảy ra với máy khách / máy chủ hơn là bắt đầu mô tả ở đây
Nếu chúng tôi chạy truy vấn sau (được chỉnh sửa để bảo vệ một số nội dung):
select *
from [big table]
where serial_number = [some number]
order by test_date desc
Truy vấn hết thời gian mỗi lần. Trong SQL Server Profiler, truy vấn được thực hiện trông như thế này với máy chủ:
exec sp_cursorprepexec @p1 output,@p2 output,NULL,N'select * .....
Bây giờ nếu bạn sửa đổi truy vấn thành, hãy nói điều này:
declare @temp int;
select * from [big table]
where serial_number = [some number]
order by test_date desc
Trình cấu hình máy chủ SQL hiển thị truy vấn được thực hiện giống như máy chủ này và nó hoạt động ngay lập tức:
exec sp_prepexec @p1 output, NULL, N'declare @temp int;select * from .....
Như một vấn đề thực tế, bạn thậm chí có thể đặt một bình luận trống ('-;') thay vì một tuyên bố tuyên bố không sử dụng và nhận được kết quả tương tự. Vì vậy, ban đầu chúng tôi đã chỉ đến bộ xử lý trước sp là nguyên nhân gốc rễ của vấn đề này, nhưng nếu bạn làm điều này:
select *
from [big table]
where serial_number = [some number]
order by Cast(test_date as smalldatetime) desc
Nó cũng hoạt động ngay lập tức (bạn có thể sử dụng nó như bất kỳ datetime
loại nào khác ), trả về kết quả sau mili giây. Và trình hồ sơ hiển thị yêu cầu đến máy chủ là:
exec sp_cursorprepexec @p1 output, @p2 output, NULL, N'select * from .....
Vì vậy, phần nào loại trừ các sp_cursorprepexec
thủ tục từ nguyên nhân đầy đủ của vấn đề. Thêm vào đó là thực tế rằng sp_cursorprepexec
nó cũng được gọi khi không sử dụng 'order by' và kết quả nó cũng được trả về ngay lập tức.
Chúng tôi đã tìm hiểu về vấn đề này khá nhiều và tôi thấy các vấn đề tương tự được đăng từ những người khác, nhưng không có vấn đề nào phá vỡ đến mức này.
Vậy những người khác đã chứng kiến hành vi này? Có ai có giải pháp tốt hơn việc đặt SQL vô nghĩa trước câu lệnh select để thay đổi hành vi không? Là SQL Server nên gọi thứ tự sau khi dữ liệu được thu thập, có vẻ như đây là một lỗi trong máy chủ đã tồn tại trong một thời gian dài. Chúng tôi đã tìm thấy hành vi này phù hợp trên nhiều bảng lớn của chúng tôi và có thể tái tạo.
Chỉnh sửa:
Tôi cũng nên thêm một đặt forceseek
vào cũng làm cho vấn đề biến mất.
Tôi nên thêm để giúp người tìm kiếm, lỗi hết thời gian ODBC được ném là: [Microsoft] [Trình điều khiển máy chủ SQL ODBC] Thao tác bị hủy
Đã thêm 10/12/2012: Vẫn đang tìm kiếm nguyên nhân gốc, (cùng với việc đã xây dựng một mẫu để cung cấp cho Microsoft, tôi sẽ đăng chéo bất kỳ kết quả nào tại đây sau khi tôi gửi). Tôi đã đào sâu vào tệp theo dõi ODBC giữa một truy vấn đang hoạt động (với một câu lệnh nhận xét / khai báo được thêm vào) và truy vấn không hoạt động. Sự khác biệt dấu vết cơ bản được đăng dưới đây. Nó xảy ra trong cuộc gọi đến cuộc gọi SQLExtendsFetch sau khi tất cả các cuộc thảo luận SQLBindCol được hoàn thành. Cuộc gọi thất bại với mã trả về -1 và luồng cha sau đó nhập SQL Hủy. Vì chúng tôi có thể tạo ra điều này với cả trình điều khiển ODBC của Máy khách gốc và Di sản, tôi vẫn chỉ ra một số vấn đề tương thích ở phía máy chủ.
(clip)
MSSQLODBCTester 1664-1718 EXIT SQLBindCol with return code 0 (SQL_SUCCESS)
HSTMT 0x001EEA10
UWORD 16
SWORD 1 <SQL_C_CHAR>
PTR 0x03259030
SQLLEN 51
SQLLEN * 0x0326B820 (0)
MSSQLODBCTester 1664-1718 ENTER SQLExtendedFetch
HSTMT 0x001EEA10
UWORD 1 <SQL_FETCH_NEXT>
SQLLEN 1
SQLULEN * 0x032677C4
UWORD * 0x032679B0
MSSQLODBCTester 1664-1fd0 ENTER SQLCancel
HSTMT 0x001EEA10
MSSQLODBCTester 1664-1718 EXIT SQLExtendedFetch with return code -1 (SQL_ERROR)
HSTMT 0x001EEA10
UWORD 1 <SQL_FETCH_NEXT>
SQLLEN 1
SQLULEN * 0x032677C4
UWORD * 0x032679B0
DIAG [S1008] [Microsoft][ODBC SQL Server Driver]Operation canceled (0)
MSSQLODBCTester 1664-1fd0 EXIT SQLCancel with return code 0 (SQL_SUCCESS)
HSTMT 0x001EEA10
MSSQLODBCTester 1664-1718 ENTER SQLErrorW
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C
SDWORD * 0x08BFFF08
WCHAR * 0x08BFF85C
SWORD 511
SWORD * 0x08BFFEE6
MSSQLODBCTester 1664-1718 EXIT SQLErrorW with return code 0 (SQL_SUCCESS)
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C [ 5] "S1008"
SDWORD * 0x08BFFF08 (0)
WCHAR * 0x08BFF85C [ 53] "[Microsoft][ODBC SQL Server Driver]Operation canceled"
SWORD 511
SWORD * 0x08BFFEE6 (53)
MSSQLODBCTester 1664-1718 ENTER SQLErrorW
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C
SDWORD * 0x08BFFF08
WCHAR * 0x08BFF85C
SWORD 511
SWORD * 0x08BFFEE6
MSSQLODBCTester 1664-1718 EXIT SQLErrorW with return code 100 (SQL_NO_DATA_FOUND)
HENV 0x001E7238
HDBC 0x001E7B30
HSTMT 0x001EEA10
WCHAR * 0x08BFFC5C
SDWORD * 0x08BFFF08
WCHAR * 0x08BFF85C
SWORD 511
SWORD * 0x08BFFEE6
(clip)
Đã thêm trường hợp Microsoft Connect 10/12/2012:
Tôi cũng cần lưu ý rằng chúng tôi đã tìm kiếm các kế hoạch truy vấn cho cả truy vấn chức năng và không hoạt động. Cả hai đều được tái sử dụng một cách thích hợp dựa trên số lượng thực hiện. Xóa các kế hoạch được lưu trữ và chạy lại không thay đổi thành công của truy vấn.
sp_executesql
và xem những gì sẽ xảy ra.
select id, test_date from [big table] where serial_number = ..... order by test_date
- Tôi chỉ tự hỏi liệu điều đóSELECT *
có ảnh hưởng tiêu cực đến hiệu suất của bạn không. Nếu bạn có chỉ mục không bao gồm trêntest_date
và chỉ mục được nhóm trênid
(giả sử đó là tên gọi), truy vấn này sẽ được bao phủ bởi chỉ mục không bao gồm đó và do đó sẽ trả về khá nhanh