Tôi có một cái nhìn lớn mà tôi sử dụng từ trong một ứng dụng. Tôi nghĩ rằng tôi đã thu hẹp vấn đề hiệu suất của mình, nhưng tôi không biết cách khắc phục nó. Một phiên bản đơn giản hóa của khung nhìn trông như thế này:
SELECT ISNULL(SEId + '-' + PEId, '0-0') AS Id,
*,
DATEADD(minute, Duration, EventTime) AS EventEndTime
FROM (
SELECT se.SEId, pe.PEId,
COALESCE(pe.StaffName, se.StaffName) AS StaffName, -- << Problem!
COALESCE(pe.EventTime, se.EventTime) AS EventTime,
COALESCE(pe.EventType, se.EventType) AS EventType,
COALESCE(pe.Duration, se.Duration) AS Duration,
COALESCE(pe.Data, se.Data) AS Data,
COALESCE(pe.Field, se.Field) AS Field,
pe.ThisThing, se.OtherThing
FROM PE pe FULL OUTER JOIN SE se
ON pe.StaffName = se.StaffName
AND pe.Duration = se.Duration
AND pe.EventTime = se.EventTime
WHERE NOT(pe.ThisThing = 1 AND se.OtherThing = 0)
) Z
Điều đó có thể không biện minh cho toàn bộ lý do cấu trúc truy vấn, nhưng có thể cho bạn một ý tưởng - chế độ xem này kết hợp với hai bảng được thiết kế rất kém mà tôi không kiểm soát được và cố gắng tổng hợp một số thông tin từ đó.
Vì vậy, vì đây là chế độ xem được sử dụng từ ứng dụng, trong khi cố gắng tối ưu hóa, tôi bọc nó trong một CHỌN khác, như thế này:
SELECT * FROM (
-- … above code …
) Q
WHERE StaffName = 'SMITH, JOHN Q'
bởi vì ứng dụng đang tìm kiếm các nhân viên cụ thể trong kết quả.
Vấn đề dường như là COALESCE(pe.StaffName, se.StaffName) AS StaffName
phần và tôi đang chọn từ chế độ xem trên StaffName
. Nếu tôi thay đổi điều đó thành pe.StaffName AS StaffName
hoặc se.StaffName AS StaffName
, các vấn đề về hiệu suất sẽ biến mất (nhưng xem cập nhật 2 bên dưới) . Nhưng điều đó sẽ không xảy ra vì một bên hay bên kia FULL OUTER JOIN
có thể bị thiếu, vì vậy một hoặc một lĩnh vực khác có thể là NULL.
Tôi có thể cấu trúc lại cái này thay thế COALESCE(…)
cái khác không, cái này sẽ được viết lại thành truy vấn con?
Ghi chú khác:
- Tôi đã thêm một số chỉ mục để khắc phục các vấn đề về hiệu năng với phần còn lại của truy vấn - không có
COALESCE
nó rất nhanh. - Hơi ngạc nhiên, nhìn vào kế hoạch thực hiện không giương cờ nào, ngay cả khi
WHERE
bao gồm cả câu hỏi và câu hỏi phụ. Tổng chi phí truy vấn con của tôi trong máy phân tích là0.0065736
. Hừm. Phải mất bốn giây để thực hiện. - Thay đổi ứng dụng để truy vấn khác nhau
(ví dụ như trả lạicó thể hoạt động, nhưng như là phương sách cuối cùng - tôi thực sự hy vọng tôi có thể tối ưu hóa chế độ xem mà không cần phải dùng đến việc chạm vào ứng dụng.pe.StaffName AS PEStaffName, se.StaffName AS SEStaffName
và thực hiệnWHERE PEStaffName = 'X' OR SEStaffName = 'X'
) - Một thủ tục được lưu trữ có thể có ý nghĩa hơn cho việc này, nhưng ứng dụng được xây dựng với Entity Framework và tôi không thể tìm ra cách làm cho nó hoạt động tốt với SP trả về loại bảng (hoàn toàn là một chủ đề khác).
Chỉ mục
Các chỉ mục tôi đã thêm cho đến nay trông giống như thế này:
CREATE NONCLUSTERED INDEX [IX_PE_EventTime]
ON [dbo].[PE] ([EventTime])
INCLUDE ([StaffName],[Duration],[EventType],[Data],[Field],[ThisThing])
CREATE NONCLUSTERED INDEX [IX_SE_EventTime]
ON [dbo].[SE] ([EventTime])
INCLUDE ([StaffName],[Duration],[EventType],[Data],[Field],[OtherThing])
Cập nhật
Tôi đã thử mô phỏng sự thay đổi bị ảnh hưởng ở trên và nó không giúp được gì. Tức là, trước đây ) Z
, tôi đã thêm AND (pe.StaffName = 'SMITH, JOHN Q' OR se.StaffName = 'SMITH, JOHN Q')
, nhưng hiệu suất là như nhau. Bây giờ tôi thực sự không biết bắt đầu từ đâu.
Cập nhật 2
Nhận xét của @ypercube về việc cần tham gia đầy đủ khiến tôi nhận ra rằng truy vấn tổng hợp của mình đã bỏ qua một thành phần có thể quan trọng. Mặc dù, vâng, tôi cần tham gia đầy đủ, thử nghiệm tôi đã thực hiện ở trên bằng cách bỏ COALESCE
và chỉ kiểm tra một mặt của giá trị không có giá trị sẽ làm cho mặt khác của tham gia đầy đủ không liên quan và trình tối ưu hóa có thể sử dụng điều này Thực tế để tăng tốc độ truy vấn. Ngoài ra, tôi đã cập nhật ví dụ để cho thấy đây StaffName
thực sự là một trong những khóa tham gia - có lẽ có ảnh hưởng đáng kể đến câu hỏi. Bây giờ tôi cũng đang nghiêng về đề nghị của anh ấy rằng việc chia nhỏ điều này thành một liên minh ba chiều thay vì tham gia đầy đủ có thể là câu trả lời, và sẽ đơn giản hóa sự phong phú của những COALESCE
gì tôi đang làm. Đang thử nó ngay bây giờ.
KeyField
, cả hai chỉ số INCLUDE
các StaffName
lĩnh vực và một số lĩnh vực khác. Tôi có thể đăng định nghĩa chỉ số trong câu hỏi. Tôi đang làm việc trên máy chủ thử nghiệm này để tôi có thể thêm bất kỳ chỉ mục nào bạn nghĩ có thể hữu ích để thử!
WHERE pe.ThisThing = 1 AND se.OtherThing = 0
điều kiện hủy FULL OUTER
tham gia và thực hiện truy vấn tương đương với tham gia bên trong. Bạn có chắc chắn cần một sự tham gia ĐẦY ĐỦ?
INNER JOIN
, LEFT JOIN
với WHERE IS NULL
kiểm tra, RIGHT JOIN với IS NULL) và sau đó UNION ALL
ba phần. Cách này sẽ không cần sử dụng COALESCE()
và nó có thể (chỉ có thể) giúp trình tối ưu hóa tìm ra cách viết lại.