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 Server가 충분하지 않을까요?

답변:


12

ForeignId, ForeignTable, IsMain에서 고유하지 않은 것으로 알려진 경우 * ExternFile는 수량을 계산하기 위해 해당 테이블을 포함해야합니다. 여러 행이 일치 할 때마다 개수에 영향을 미칩니다.

단순화를
위한 SQL Server 디자인의 단순화 단순화 (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

이제 쿼리가 더 효과적입니다. 값이 고유하지 않기 때문에 고유 인덱스를 추가 할 수 없습니다. 조건에서 조합하는 경우에만 고유했으며 위에서 언급 한 것처럼 고유 하지 않습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.