Tôi có một truy vấn trong đó việc sử dụng select *
không chỉ đọc ít hơn rất nhiều mà còn sử dụng thời gian CPU ít hơn đáng kể so với sử dụng select c.Foo
.
Đây là truy vấn:
select top 1000 c.ID
from ATable a
join BTable b on b.OrderKey = a.OrderKey and b.ClientId = a.ClientId
join CTable c on c.OrderId = b.OrderId and c.ShipKey = a.ShipKey
where (a.NextAnalysisDate is null or a.NextAnalysisDate < @dateCutOff)
and b.IsVoided = 0
and c.ComplianceStatus in (3, 5)
and c.ShipmentStatus in (1, 5, 6)
order by a.LastAnalyzedDate
Điều này kết thúc với 2.473.658 lượt đọc logic, chủ yếu trong Bảng B. Nó sử dụng 26.562 CPU và có thời lượng 7.965.
Đây là kế hoạch truy vấn được tạo:
Trên PasteThePlan: https://www.brentozar.com/pastetheplan/?id=BJAp2mQIQ
Khi tôi thay đổi c.ID
để *
, truy vấn kết thúc với 107.049 logic đọc, khá đồng đều lây lan giữa tất cả ba bảng. Nó sử dụng CPU 4.266 và có thời lượng 1.147.
Đây là kế hoạch truy vấn được tạo:
Trên PasteThePlan: https://www.brentozar.com/pastetheplan/?id=SyZYn7QUQ
Tôi đã cố gắng sử dụng các gợi ý truy vấn được đề xuất bởi Joe Obbish, với các kết quả sau:
select c.ID
không có gợi ý: https://www.brentozar.com/pastetheplan/?id=SJfBdOELm
select c.ID
với gợi ý: https://www.brentozar.com/pastetheplan/ ? id = B1W ___ N87
select *
không có gợi ý: https://www.brentozar.com/pastetheplan/?id=HJ6qddEIm
select *
với gợi ý: https://www.brentozar.com/pastetheplan/?id=rJhhudNIQ
Sử dụng OPTION(LOOP JOIN)
gợi ý với select c.ID
việc giảm đáng kể số lần đọc so với phiên bản mà không có gợi ý, nhưng nó vẫn đang thực hiện khoảng 4 lần số lần đọc select *
truy vấn mà không có bất kỳ gợi ý nào. Thêm OPTION(RECOMPILE, HASH JOIN)
vào select *
truy vấn làm cho nó thực hiện tồi tệ hơn nhiều so với bất kỳ điều gì khác mà tôi đã thử.
Sau khi cập nhật số liệu thống kê trên các bảng và chỉ mục của chúng bằng cách sử dụng WITH FULLSCAN
, select c.ID
truy vấn sẽ chạy nhanh hơn nhiều:
select c.ID
trước khi cập nhật: https://www.brentozar.com/pastetheplan/?id=SkiYoOEUm
select *
trước khi cập nhật: https://www.brentozar.com/ pastetheplan /? id = ryrvodEUX
select c.ID
sau khi cập nhật: https://www.brentozar.com/pastetheplan/?id=B1MRoO487
select *
sau khi cập nhật: https://www.brentozar.com/pastetheplan/?id=Hk7si_V8m
select *
vẫn vượt trội select c.ID
về tổng thời lượng và tổng số lần đọc ( select *
có khoảng một nửa số lần đọc) nhưng nó sử dụng nhiều CPU hơn. Nhìn chung, chúng gần hơn nhiều so với trước khi cập nhật, tuy nhiên các kế hoạch vẫn khác nhau.
Hành vi tương tự được nhìn thấy vào năm 2016 chạy trong chế độ Tương thích 2014 và vào năm 2014. Điều gì có thể giải thích cho sự chênh lệch giữa hai kế hoạch? Có thể là các chỉ mục "chính xác" chưa được tạo ra? Số liệu thống kê có thể hơi lỗi thời gây ra điều này?
Tôi đã cố gắng di chuyển các vị từ lên đến ON
một phần của phép nối, theo nhiều cách, nhưng kế hoạch truy vấn là giống nhau mỗi lần.
Sau khi xây dựng lại chỉ số
Tôi xây dựng lại tất cả các chỉ mục trên ba bảng liên quan đến truy vấn. c.ID
vẫn đang đọc nhiều nhất (gấp đôi số lần *
), nhưng mức sử dụng CPU chỉ bằng một nửa *
phiên bản. Các c.ID
phiên bản cũng đổ vào tempdb trên việc phân loại ATable
:
c.ID
: https://www.brentozar.com/pastetheplan/?id=HyHIeDO87
*
: https://www.brentozar.com/pastetheplan/?id=rJ4deDOIQ
Tôi cũng đã cố gắng buộc nó hoạt động mà không có sự song song và điều đó đã cho tôi truy vấn hoạt động tốt nhất: https://www.brentozar.com/pastetheplan/?id=SJn9-vuLX
Tôi nhận thấy số lần thực thi của các toán tử SAU khi tìm kiếm chỉ mục lớn đang thực hiện lệnh chỉ được thực hiện 1.000 lần trong phiên bản đơn luồng, nhưng đã làm nhiều hơn đáng kể trong phiên bản Song song, giữa 2.622 và 4.315 lần thực thi của các toán tử khác nhau.
select c.ID
truy vấn nhanh hơn nhiều, nhưng nó vẫn đang thực hiện một số công việc bổ sung màselect *
truy vấn, không có gợi ý, thực hiện.