Bạn đang sử dụng phiên bản SQL Server mới hơn nên kế hoạch thực tế cung cấp cho bạn nhiều thông tin. Xem dấu hiệu thận trọng trên các SELECT
nhà điều hành? Điều đó có nghĩa là SQL Server đã tạo một cảnh báo có thể ảnh hưởng đến hiệu năng truy vấn. Bạn nên luôn luôn nhìn vào:
<Warnings>
<PlanAffectingConvert ConvertIssue="Seek Plan" Expression="[s].[logger_uuid]=CONVERT_IMPLICIT(nchar(17),[d].[uuid],0)" />
<PlanAffectingConvert ConvertIssue="Seek Plan" Expression="CONVERT_IMPLICIT(nvarchar(100),[d].[name],0)=[g].[name]" />
</Warnings>
Có hai loại chuyển đổi dữ liệu gây ra bởi lược đồ của bạn. Dựa trên các cảnh báo tôi nghi ngờ rằng tên đó thực sự là một NVARCHAR(100)
và logger_uuid
là một NCHAR(17)
. Lược đồ bảng được đăng trong câu hỏi có thể không chính xác. Bạn nên hiểu nguyên nhân gốc rễ tại sao các chuyển đổi này xảy ra và khắc phục nó. Một số loại chuyển đổi loại dữ liệu ngăn chặn tìm kiếm chỉ mục, dẫn đến các vấn đề ước tính cardinality và gây ra các vấn đề khác.
Một điều quan trọng khác để kiểm tra là số liệu thống kê chờ đợi. Bạn có thể thấy những người trong các chi tiết của các SELECT
nhà điều hành là tốt. Đây là XML cho các số liệu thống kê chờ đợi của bạn và thời gian dành cho truy vấn:
<WaitStats>
<Wait WaitType="RESOURCE_GOVERNOR_IDLE" WaitTimeMs="49515" WaitCount="3773" />
<Wait WaitType="SOS_SCHEDULER_YIELD" WaitTimeMs="57164" WaitCount="2466" />
</WaitStats>
<QueryTimeStats ElapsedTime="67135" CpuTime="10007" />
Tôi không phải là người trên đám mây nhưng có vẻ như truy vấn của bạn không thể tham gia đầy đủ vào CPU . Điều đó có thể liên quan đến lớp Azure hiện tại của bạn. Truy vấn chỉ cần khoảng 10 giây CPU khi thực thi nhưng phải mất 67 giây. Tôi tin rằng 50 giây thời gian đó đã được sử dụng để tiết kiệm và 7 giây thời gian đó được trao cho bạn nhưng được sử dụng cho các truy vấn khác đang chạy đồng thời. Tin xấu là truy vấn chậm hơn có thể là do tầng của bạn. Tin tốt là mọi sự giảm CPU đều có thể dẫn đến giảm 5 lần thời gian chạy. Nói cách khác, nếu bạn có thể nhận được truy vấn để sử dụng 1 giây CPU thì bạn có thể thấy thời gian chạy khoảng 5 giây.
Tiếp theo, bạn có thể xem thuộc tính Thống kê thời gian thực trong chi tiết nhà điều hành của bạn để xem thời gian sử dụng CPU. Gói của bạn sử dụng chế độ hàng, vì vậy thời gian CPU cho một toán tử là tổng thời gian mà toán tử đó cũng như các con của nó sử dụng. Đây là một kế hoạch tương đối đơn giản, do đó, không mất nhiều thời gian để phát hiện ra rằng quét chỉ mục được nhóm logger_data
sử dụng thời gian CPU là 6527 ms. Phép nối vòng lặp gọi nó sử dụng 10006 ms thời gian CPU, vì vậy tất cả CPU của truy vấn của bạn được sử dụng ở bước đó. Một manh mối khác cho thấy có gì đó không ổn ở bước đó có thể được tìm thấy bằng cách xem xét độ dày của các mũi tên tương đối:
Rất nhiều hàng được trả về từ toán tử đó, vì vậy nó đáng để xem xét chi tiết. Nhìn vào số lượng hàng thực tế để quét chỉ mục được nhóm, bạn có thể thấy rằng 14088885 hàng đã được trả về và 14100798 hàng đã được đọc. Tuy nhiên, số lượng thẻ bảng chỉ là 484804 hàng. Theo trực giác có vẻ khá kém hiệu quả, phải không? Quét chỉ mục cụm trả về nhiều hơn nhiều so với số lượng hàng trong bảng. Một số kế hoạch khác với loại tham gia hoặc phương thức truy cập khác trên bảng có thể sẽ hiệu quả hơn.
Tại sao SQL Server đọc và trả về nhiều hàng như vậy? Chỉ số cụm nằm ở phía bên trong của một vòng lặp lồng nhau. Có 38 hàng được trả về bởi phía bên ngoài của vòng lặp (quét trên logger
bảng) để quét trên logger_data
thực hiện 38 lần. 484804 * 38 = 18422514 khá gần với số lượng hàng đã đọc. Vậy tại sao SQL Server lại chọn một kế hoạch như vậy mà cảm thấy không hiệu quả? Nó thậm chí còn ước tính rằng nó sẽ thực hiện 57 lần quét bảng, vì vậy có thể cho rằng kế hoạch mà bạn có được hiệu quả hơn so với nghi ngờ.
Bạn có thể đã tự hỏi tại sao có một TOP
nhà điều hành trong kế hoạch của bạn. SQL Server đã giới thiệu một mục tiêu hàng khi tạo kế hoạch truy vấn cho truy vấn của bạn. Điều này có thể chi tiết hơn bạn muốn, nhưng phiên bản ngắn là SQL Server không phải lúc nào cũng cần trả về tất cả các hàng từ quét chỉ mục cụm. Đôi khi nó có thể dừng sớm nếu nó chỉ cần một số hàng cố định và nó tìm thấy những hàng đó trước khi nó kết thúc quá trình quét. Việc quét không tốn kém nếu nó có thể dừng sớm để chi phí cho nhà điều hành được giảm giá theo công thức khi có mục tiêu hàng. Nói cách khác, SQL Server dự kiến sẽ quét chỉ mục được nhóm 57 lần, nhưng nó nghĩ rằng nó sẽ tìm thấy một hàng duy nhất mà nó cần rất nhanh. Nó chỉ cần một hàng duy nhất từ mỗi lần quét do sự hiện diện củaTOP
nhà điều hành.
Bạn có thể làm cho truy vấn của mình nhanh hơn bằng cách khuyến khích trình tối ưu hóa truy vấn chọn một gói không quét logger_data
bảng 38 lần. Điều này có thể đơn giản như loại bỏ các chuyển đổi loại dữ liệu. Điều đó có thể cho phép SQL Server thực hiện tìm kiếm chỉ mục thay vì quét. Nếu không, hãy sửa các chuyển đổi và tạo chỉ mục bao phủ cho logger_data
:
CREATE INDEX IX ON logger_data (category_name, logger_uuid);
Trình tối ưu hóa truy vấn chọn một kế hoạch dựa trên chi phí. Việc thêm chỉ mục này khiến cho không thể có được kế hoạch chậm mà nhiều lần quét trên logger_data vì sẽ rẻ hơn khi truy cập vào bảng thông qua tìm kiếm chỉ mục thay vì quét chỉ mục theo cụm.
Nếu bạn không thể thêm chỉ mục, bạn có thể xem xét thêm gợi ý truy vấn để vô hiệu hóa việc giới thiệu mục tiêu hàng : USE HINT('DISABLE_OPTIMIZER_ROWGOAL'))
. Bạn chỉ nên làm điều này nếu bạn cảm thấy thoải mái với khái niệm mục tiêu hàng và hiểu chúng. Thêm gợi ý đó sẽ dẫn đến một kế hoạch khác, nhưng tôi không thể nói nó sẽ hiệu quả như thế nào.