Tại sao kế hoạch thực hiện truy vấn SELECT COUNT () bao gồm bảng được nối trái?


9

Trong SQL Server 2012, tôi có hàm có giá trị bảng với phép nối với bảng khác tôi cần đếm số lượng hàng cho 'hàm có giá trị bảng' này. Khi tôi kiểm tra kế hoạch thực hiện, tôi có thể thấy bảng tham gia bên trái. Tại sao? Làm thế nào có thể trái bảng tham gia ảnh hưởng số lượng hàng trả về? Tôi hy vọng rằng công cụ db không cần phải đánh giá bảng khớp bên trái trong truy vấn SELECT Count (..).

Select count(realtyId) FROM [dbo].[GetFilteredRealtyFulltext]('"praha"')

Kế hoạch thực hiện:

nhập mô tả hình ảnh ở đây

Hàm có giá trị bảng:

CREATE FUNCTION [dbo].[GetFilteredRealtyFulltext]
(@criteria nvarchar(4000))
RETURNS TABLE
AS
RETURN (SELECT 
realty.Id AS realtyId,
realty.OwnerId,
realty.Caption AS realtyCaption,
realty.BusinessCategory,
realty.Created,
realty.LastChanged,
realty.LastChangedType,
realty.Price,
realty.Pricing,
realty.PriceCurrency,
realty.PriceNote,
realty.PricePlus,
realty.OfferState,
realty.OrderCode,
realty.PublishAddress,
realty.PublishMap,
realty.AreaLand,
realty.AreaCover,
realty.AreaFloor,
realty.Views,
realty.TopPoints,
realty.Radius,
COALESCE(realty.Wgs84X, ruian_cobce.Wgs84X, ruian_obec.Wgs84X) as Wgs84X,
COALESCE(realty.Wgs84Y, ruian_cobce.Wgs84Y, ruian_obec.Wgs84Y) as Wgs84Y,
realty.krajId,
realty.okresId,
realty.obecId,
realty.cobceId,
IsNull(CONVERT(int,realty.Ranking),0) as Ranking,

realty.energy_efficiency_rating,
realty.energy_performance_attachment,
realty.energy_performance_certificate,
realty.energy_performance_summary,

Category.Id AS CategoryId,
Category.ParentCategoryId,
Category.WholeName,
okres.nazev AS okres,
ruian_obec.nazev AS obec,
ruian_cobce.nazev AS cobce,
ExternFile.ServerPath,
Person.ParentPersonId,
( COALESCE(ftR.Rank,0) + COALESCE(ftObec.Rank,0) + COALESCE(ftOkres.Rank,0) + COALESCE(ftpobvod.Rank,0)) AS FtRank

FROM realty
JOIN Category ON realty.CategoryId = Category.Id
LEFT JOIN ruian_cobce ON realty.cobceId = ruian_cobce.cobce_kod
LEFT JOIN ruian_obec ON realty.obecId = ruian_obec.obec_kod
LEFT JOIN okres ON realty.okresId = okres.okres_kod
LEFT JOIN ExternFile ON realty.Id = ExternFile.ForeignId AND ExternFile.IsMain = 1 AND ExternFile.ForeignTable = 5
INNER JOIN Person ON realty.OwnerId = Person.Id
Left JOIN CONTAINSTABLE(Realty, *, @criteria) ftR ON realty.Id = ftR.[Key] 
Left JOIN CONTAINSTABLE(ruian_obec, *, @criteria) ftObec ON realty.obecId = ftObec.[Key] 
Left JOIN CONTAINSTABLE(Okres, *, @criteria) ftOkres ON realty.okresId = ftOkres.[Key]
Left JOIN CONTAINSTABLE(pobvod, *, @criteria) ftpobvod ON realty.pobvodId = ftpobvod.[Key]
WHERE Person.ConfirmStatus = 1
AND ( COALESCE(ftR.Rank,0) + COALESCE(ftObec.Rank,0) + COALESCE(ftOkres.Rank,0) + COALESCE(ftpobvod.Rank,0))  > 0
)

CẬP NHẬT:

Tôi thêm chỉ mục duy nhất để làm theo ý tưởng của Rob Farley:

 Create unique nonclustered index ExternFileIsMainUnique ON ExternFile(ForeignId) WHERE IsMain = 1 AND ForeignTable = 5

Và được lập chỉ mục bởi DB Engine:

CREATE NONCLUSTERED INDEX [RealtyOwnerLocation] ON [dbo].[Realty]

([Chủ sở hữu] ASC) BAO GỒM ([Id], [okresId], [obecId], [pobvodId]) GO

Để đơn giản, tôi loại bỏ điều kiện

WHERE Person.ConfirmStatus = 1

từ chức năng có giá trị theo bảng ở trên.

Bây giờ kế hoạch thực hiện đơn giản hơn nhiều nhưng nó vẫn chạm vào bảng ExternFile:

nhập mô tả hình ảnh ở đây

Có lẽ máy chủ sql không đủ thông minh?

Câu trả lời:


12

Nếu ForeignId, ForeignTable, IsMainkhông biết * là duy nhất ExternFile, thì QO sẽ cần bao gồm bảng đó để tính ra số đếm. Bất cứ khi nào nhiều hàng khớp nhau, số lượng sẽ bị ảnh hưởng.

Tham gia đơn giản hóa trong
Thiết kế máy chủ SQL để đơn giản hóa (ghi SQLBits)


* Trình tối ưu hóa hiện không nhận ra các chỉ mục duy nhất được lọc là duy nhất

CẬP NHẬT (bởi OP) : Giải pháp là thay đổi dòng trong truy vấn từ LEFT THAM GIA (có thể tạo ra nhiều hàng):

LEFT JOIN ExternFile ON realty.Id = ExternFile.ForeignId AND ExternFile.IsMain = 1 AND ExternFile.ForeignTable = 5

thành OUTER ỨNG DỤNG với TOP (tạo ra một hàng và không ảnh hưởng đến COUNT)

OUTER APPLY (SELECT TOP (1) ServerPath FROM ExternFile WHERE ForeignId = realty.Id AND IsMain = 1 AND ForeignTable = 5) AS ExternFile

Các truy vấn bây giờ hiệu quả hơn. Việc thêm một chỉ mục duy nhất không thể được thực hiện, bởi vì các giá trị không phải là duy nhất, chúng chỉ duy nhất để kết hợp trong điều kiện và điều này không được coi là duy nhất như đã đề cập ở trên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.