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
)

更新:

Rob Farleyのアイデアに従うために、一意のインデックスを追加します。

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

そして、DBエンジンによって提案されたインデックス:

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

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

簡単にするために、条件を削除します

WHERE Person.ConfirmStatus = 1

上記の表の値の関数から。

これで実行計画ははるかに単純になりますが、それでもテーブルExternFileに影響します。

ここに画像の説明を入力してください

たぶんSQLサーバーは十分に賢くないですか?

回答:


12

ForeignId, ForeignTable, IsMainで一意であることがわからない* 場合ExternFile、QOはカウントを計算するためにそのテーブルを含める必要があります。複数の行が一致する場合は常に、カウントが影響を受けます。


簡素化のためのSQL Server DesigningのSimplificationへの参加(SQLBits記録)


* オプティマイザは現在、フィルタリングれた一意のインデックスを一意として認識しません

UPDATE(OPによる):解決策は、クエリの行をLEFT JOINから変更することです(複数行を生成する可能性があります):

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

TOPを指定したOUTER APPLYへ(1行を生成し、COUNTには影響しません)

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

クエリがより効果的になりました。一意のインデックスを追加できませんでした。値が一意ではなかったため、条件での組み合わせに対してのみ一意であり、これは上記のように一意とは見なさません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.