Чому план виконання запиту SELECT COUNT () включає ліву об'єднану таблицю?


9

У SQL Server 2012 у мене є функція, що оцінюється за таблицею, з приєднанням до іншої таблиці, мені потрібно порахувати кількість рядків для цієї «функції, що оцінюється за таблицею». Перевіряючи план виконання, я бачу ліву таблицю приєднання. Чому? Як може ліва об’єднана таблиця впливати на кількість повернутих рядків? Я б очікував, що двигуну db не потрібно оцінювати ліву спільну таблицю у запиті SELECT count (..).

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

План виконання:

введіть тут опис зображення

Функція в таблиці:

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
)

ОНОВЛЕННЯ:

Я додаю унікальний індекс, щоб наслідувати ідею Роб Фарлі:

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

І індексовано запропонованим DB Engine:

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

([OwnerId] ASC) ВКЛЮЧИТЬ ([Id], [okresId], [obecId], [pobvodId]) GO

Для простоти я знімаю умову

WHERE Person.ConfirmStatus = 1

з висунутої вище значення функції.

Тепер план виконання набагато простіший, але він все ще торкається таблиці ExternFile:

введіть тут опис зображення

Можливо, сервер sql недостатньо розумний?

Відповіді:


12

Якщо ForeignId, ForeignTable, IsMainневідомо *, щоб бути унікальним ExternFile, тоді QO потрібно буде включити цю таблицю, щоб обчислити підрахунок. Кожен раз, коли збігається декілька рядків, це вплине на підрахунок.

Приєднайтеся до спрощення в SQL Server Design
для спрощення (запис SQLBits)


* Оптимізатор не визнає відфільтровані унікальні індекси як унікальні

ОНОВЛЕННЯ (OP) : Рішення полягає в зміні рядка в запиті з LEFT JOIN (який може створити кілька рядків):

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

ВИКОРИСТОВУВАТИ ЗАЯВКУ з TOP (які створюють один рядок і не впливають на COUNT)

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

Тепер запит є більш ефективним. Додавання унікального індексу зробити не вдалося, оскільки значення не були унікальними, вони були унікальними лише для комбінації в умові, і це не вважається унікальним, як згадувалося вище.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.