Warum enthält der Abfrageausführungsplan SELECT COUNT () eine linksverknüpfte Tabelle?


9

In SQL Server 2012 habe ich eine Tabellenwertfunktion mit Verknüpfung zu einer anderen Tabelle. Ich muss die Anzahl der Zeilen für diese 'Tabellenwertfunktion' zählen. Wenn ich den Ausführungsplan überprüfe, sehe ich die linke Verknüpfungstabelle. Warum? Wie kann die linksverknüpfte Tabelle die Anzahl der zurückgegebenen Zeilen beeinflussen? Ich würde erwarten, dass die DB-Engine die linke gemeinsame Tabelle in der SELECT count (..) Abfrage nicht auswerten muss.

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

Der Ausführungsplan:

Geben Sie hier die Bildbeschreibung ein

Die Tabellenwertfunktion:

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
)

AKTUALISIEREN:

Ich füge einen einzigartigen Index hinzu, um der Idee von Rob Farley zu folgen:

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

Und indiziert von DB Engine vorgeschlagen:

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

([OwnerId] ASC) INCLUDE ([Id], [okresId], [obecId], [pobvodId]) GO

Der Einfachheit halber entferne ich die Bedingung

WHERE Person.ConfirmStatus = 1

von der oben angegebenen Wertfunktion.

Jetzt ist der Ausführungsplan viel einfacher, berührt aber immer noch die Tabelle ExternFile:

Geben Sie hier die Bildbeschreibung ein

Vielleicht ist SQL Server nicht klug genug?

Antworten:


12

Wenn ForeignId, ForeignTable, IsMainnicht bekannt ist, dass * eindeutig ist ExternFile, muss die Qualitätssicherung diese Tabelle einschließen, um die Anzahl zu ermitteln. Jedes Mal, wenn mehrere Zeilen übereinstimmen, wird die Anzahl beeinflusst.

Vereinfachen Sie die Vereinfachung in SQL Server
Designing zur Vereinfachung (SQLBits-Aufzeichnung)


* Das Optimierungsprogramm erkennt gefilterte eindeutige Indizes derzeit nicht als eindeutig

UPDATE (von OP) : Die Lösung besteht darin, die Zeile in der Abfrage von LEFT JOIN zu ändern (wodurch mehrere Zeilen erzeugt werden können):

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

OUTER APPLY with TOP (die eine Zeile erzeugen und COUNT nicht beeinflussen)

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

Die Abfrage ist jetzt effektiver. Das Hinzufügen eines eindeutigen Index konnte nicht durchgeführt werden, da die Werte nicht eindeutig waren, sondern nur für die Kombination in der Bedingung eindeutig waren und dies nicht wie oben erwähnt als eindeutig angesehen wird.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.