Tôi có chế độ xem chạy nhanh (vài giây) cho tối đa 41 bản ghi (ví dụ TOP 41:) nhưng mất vài phút cho 44 bản ghi trở lên, với kết quả trung gian nếu chạy với TOP 42hoặc TOP 43. Cụ thể, nó sẽ trả lại 39 bản ghi đầu tiên trong vài giây, sau đó tạm dừng gần ba phút trước khi trả lại các bản ghi còn lại. Mẫu này giống nhau khi truy vấn TOP 44hoặc TOP 100.
Chế độ xem này ban đầu xuất phát từ chế độ xem cơ sở, thêm vào cơ sở chỉ một bộ lọc, bộ lọc cuối cùng trong mã bên dưới. Dường như không có sự khác biệt nếu tôi xâu chuỗi khung nhìn con từ cơ sở hoặc nếu tôi viết khung nhìn con với mã từ cơ sở được xếp hàng. Chế độ xem cơ sở trả về 100 bản ghi chỉ trong vài giây. Tôi muốn nghĩ rằng tôi có thể khiến cho chế độ xem trẻ em chạy nhanh như cơ sở, không chậm hơn 50 lần. Có ai nhìn thấy loại hành vi này? Bất kỳ dự đoán là nguyên nhân hoặc giải quyết?
Hành vi này đã được nhất quán trong vài giờ qua khi tôi đã kiểm tra các truy vấn có liên quan, mặc dù số lượng hàng được trả về trước khi mọi thứ bắt đầu chậm lại đã tăng giảm nhẹ. Đây không phải là mới; Bây giờ tôi đang xem xét vì tổng thời gian chạy đã được chấp nhận (<2 phút), nhưng ít nhất tôi đã thấy sự tạm dừng này trong các tệp nhật ký liên quan trong nhiều tháng.
Chặn
Tôi chưa bao giờ thấy truy vấn bị chặn và vấn đề tồn tại ngay cả khi không có hoạt động nào khác trên cơ sở dữ liệu (như được xác thực bởi sp_WhoIsActive). Chế độ xem cơ bản bao gồm NOLOCKtrong suốt, cho những gì đáng giá.
Truy vấn
Đây là phiên bản rút gọn của chế độ xem con, với chế độ xem cơ bản được xếp hàng để đơn giản. Nó vẫn thể hiện bước nhảy trong thời gian chạy ở khoảng 40 hồ sơ.
SELECT TOP 100 PERCENT
Map.SalesforceAccountID AS Id,
CAST(C.CustomerID AS NVARCHAR(255)) AS Name,
CASE WHEN C.StreetAddress = 'Unknown' THEN '' ELSE C.StreetAddress END AS BillingStreet,
CASE WHEN C.City = 'Unknown' THEN '' ELSE SUBSTRING(C.City, 1, 40) END AS BillingCity,
SUBSTRING(C.Region, 1, 20) AS BillingState,
CASE WHEN C.PostalCode = 'Unknown' THEN '' ELSE SUBSTRING(C.PostalCode, 1, 20) END AS BillingPostalCode,
CASE WHEN C.Country = 'Unknown' THEN '' ELSE SUBSTRING(C.Country, 1, 40) END AS BillingCountry,
CASE WHEN C.PhoneNumber = 'Unknown' THEN '' ELSE C.PhoneNumber END AS Phone,
CASE WHEN C.FaxNumber = 'Unknown' THEN '' ELSE C.FaxNumber END AS Fax,
TransC.WebsiteAddress AS Website,
C.AccessKey AS AccessKey__c,
CASE WHEN dbo.ValidateEMail(C.EMailAddress) = 1 THEN C.EMailAddress END, -- Removing this UDF does not speed things
TransC.EmailSubscriber
-- A couple dozen additional TransC fields
FROM
WarehouseCustomers AS C WITH (NOLOCK)
INNER JOIN TransactionalCustomers AS TransC WITH (NOLOCK) ON C.CustomerID = TransC.CustomerID
LEFT JOIN Salesforce.AccountsMap AS Map WITH (NOLOCK) ON C.CustomerID = Map.CustomerID
WHERE
C.DateMadeObsolete IS NULL
AND C.EmailAddress NOT LIKE '%@volusion.%'
AND C.AccessKey IN ('C', 'R')
AND C.CustomerID NOT IN (243566) -- Exclude specific test records
AND EXISTS (SELECT * FROM Orders AS O WHERE C.CustomerID = O.CustomerID AND O.OrderDate >= '2010-06-28') -- Only count customers who've placed a recent order
AND Map.SalesforceAccountID IS NULL -- Only count customers not already uploaded to Salesforce
-- Removing the ORDER BY clause does not speed things up
ORDER BY
C.CustomerID DESC
Id IS NULLBộ lọc đó loại bỏ hầu hết các hồ sơ được trả về BaseView; không có TOPđiều khoản, họ trả lại 1.100 hồ sơ và 267K tương ứng.
Số liệu thống kê
Khi chạy TOP 40:
SQL Server parse and compile time: CPU time = 234 ms, elapsed time = 247 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms.
(40 row(s) affected)
Table 'CustomersHistory'. Scan count 2, logical reads 39112, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Orders'. Scan count 1, logical reads 752, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'AccountsMap'. Scan count 1, logical reads 458, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times: CPU time = 2199 ms, elapsed time = 7644 ms.
Khi chạy TOP 45:
(45 row(s) affected)
Table 'CustomersHistory'. Scan count 2, logical reads 98268, physical reads 1, read-ahead reads 3, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Orders'. Scan count 1, logical reads 1788, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'AccountsMap'. Scan count 1, logical reads 2152, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times: CPU time = 41980 ms, elapsed time = 177231 ms.
Tôi ngạc nhiên khi thấy số lần đọc nhảy ~ 3x cho sự khác biệt khiêm tốn này trong sản lượng thực tế.
So sánh các kế hoạch thực hiện, chúng giống nhau ngoài số lượng hàng được trả về. Như với các số liệu thống kê ở trên, số hàng thực tế cho các bước đầu tiên cao hơn đáng kể trong TOP 45truy vấn, không chỉ cao hơn 12,5%.
Trong phác thảo, nó đang quét một chỉ mục bao trùm từ Đơn hàng, tìm kiếm các bản ghi tương ứng từ WarehouseCustomers; kết nối vòng lặp này với TransactionalCustomers (truy vấn từ xa, kế hoạch chính xác không xác định); và hợp nhất điều này với quét bảng của MapMap. Truy vấn từ xa là 94% chi phí ước tính.
Ghi chú linh tinh
Trước đó, khi tôi thực hiện nội dung mở rộng của chế độ xem dưới dạng truy vấn độc lập, nó chạy khá nhanh: 13 giây cho 100 bản ghi. Bây giờ tôi đang thử nghiệm phiên bản rút gọn của truy vấn, không có truy vấn con và truy vấn đơn giản hơn nhiều này mất ba phút để yêu cầu trả về hơn 40 hàng, ngay cả khi chạy dưới dạng truy vấn độc lập.
Chế độ xem con bao gồm số lần đọc đáng kể (~ 1M mỗi sp_WhoIsActive), nhưng trên máy này (tám lõi, RAM 32 GB, hộp SQL chuyên dụng 95%) thường không phải là vấn đề.
Tôi đã bỏ và tạo lại cả hai lần xem, không có thay đổi.
Dữ liệu không bao gồm bất kỳ trường văn bản hoặc BLOB. Một lĩnh vực liên quan đến UDF; loại bỏ nó không ngăn chặn tạm dừng.
Thời gian được tính tương tự cho dù truy vấn trên máy chủ chính nó, hoặc trên máy trạm của tôi 1.400 dặm, vì vậy sự chậm trễ dường như là vốn có trong truy vấn bản thân chứ không phải gửi kết quả cho khách hàng.
Ghi chú Re: Giải pháp
Việc khắc phục kết thúc rất đơn giản: thay thế LEFT JOINthành Map bằng một NOT EXISTSmệnh đề. Điều này chỉ gây ra một sự khác biệt nhỏ trong kế hoạch truy vấn, tham gia vào bảng Giao dịch khách hàng (một truy vấn từ xa) sau khi tham gia vào bảng Bản đồ thay vì trước đó. Điều này có thể có nghĩa là nó chỉ yêu cầu các bản ghi cần thiết từ máy chủ từ xa, điều này sẽ cắt giảm âm lượng truyền đi ~ 100 lần.
Thông thường tôi là người đầu tiên cổ vũ cho NOT EXISTS; nó thường nhanh hơn một LEFT JOIN...WHERE ID IS NULLcấu trúc và nhỏ gọn hơn một chút. Trong trường hợp này, thật bất tiện vì truy vấn vấn đề được xây dựng trên chế độ xem hiện có và trong khi trường cần cho chống tham gia được hiển thị bởi chế độ xem cơ sở, thì lần đầu tiên chuyển từ số nguyên sang văn bản. Vì vậy, để có hiệu suất tốt, tôi phải bỏ mẫu hai lớp và thay vào đó có hai khung nhìn gần giống nhau, với khung thứ hai bao gồm NOT EXISTSmệnh đề.
Cảm ơn tất cả sự giúp đỡ của bạn trong việc khắc phục sự cố này! Nó có thể quá cụ thể với hoàn cảnh của tôi để giúp đỡ bất cứ ai khác, nhưng hy vọng là không. Nếu không có gì khác, đó là một ví dụ về NOT EXISTSviệc nhanh hơn một chút so với LEFT JOIN...WHERE ID IS NULL. Nhưng bài học thực sự có lẽ là đảm bảo rằng các truy vấn từ xa được tham gia hiệu quả nhất có thể; kế hoạch truy vấn tuyên bố rằng nó chiếm 2% chi phí, nhưng không phải lúc nào nó cũng ước tính chính xác.