2012-01-03 3 views
3

LLBL에서 많은 수의 느린 프리 페치 쿼리를 처리하고 있습니다. 여기서 생성 된 SQL의 단순화 된 버전입니다 :하위 쿼리 IN 절이 느림?

SELECT DISTINCT 
    Column1 
FROM 
    Table1 
WHERE 
Table1.Table2ID IN 
(
    SELECT Table2.Table2ID AS Table2ID 
    FROM 
     Table2 
     INNER JOIN Table1 ON Table2.Table2ID=Table1.Table2ID 
     INNER JOIN 
     (
      SELECT DISTINCT 
       Table1.Table2ID AS Table2ID, 
       MAX(Table1.EffectiveDate) AS EffectiveDate 
      FROM Table1 
      WHERE Table1.EffectiveDate <= '2012-01-03 00:00:00:000' 
      GROUP BY Table1.Table2ID 
     ) MaxEffective 
     ON 
      MaxEffective.Table2ID = Table1.Table2ID 
      AND MaxEffective.EffectiveDate = Table1.EffectiveDate 
) 

내가 찾는거야 것은 서브 쿼리가 빠르게 실행하는 내가 실제 결과와 그 하위 쿼리를 대체 할 경우, 외부 쿼리가 빠릅니다. 그러나 함께, 그들은 느립니다.

조금 도움이 된 데이터베이스 엔진 튜닝 어드바이저를 실행했지만 여전히 느립니다.

저는 실행 계획을 잘 이해하지 못하고 있지만 Table1에서 인덱스 탐색을하는 데는 대부분 시간이 소요됩니다.

상관이없는 하위 쿼리이므로 더 빨리 실행할 것으로 예상했습니다. 내가 보지 못하는게 있니?

바로 SQL이라면 쿼리를 다시 작성하고 조인 할 것이지만 LLBL로 인해 막을 수 있습니다. 조인을 강제로 수행하는 데 사용할 수있는 설정이 있습니까? SQL Server가 조인과 동일한 실행 계획을 생성하지 않는 이유가 있습니까? 생성 문에 대한

실제 쿼리 편집 ...

SELECT DISTINCT 
    ResidentialComponentValues.ResidentialComponentValueID AS ResidentialComponentValueId, 
    ResidentialComponentValues.ResidentialComponentTypeID AS ResidentialComponentTypeId, 
    ResidentialComponentValues.Value, 
    ResidentialComponentValues.Story, 
    ResidentialComponentValues.LastUpdated, 
    ResidentialComponentValues.LastUpdatedBy, 
    ResidentialComponentValues.ConcurrencyTimestamp, 
    ResidentialComponentValues.EffectiveDate, 
    ResidentialComponentValues.DefaultQuantity 
FROM 
ResidentialComponentValues 
WHERE 
ResidentialComponentValues.ResidentialComponentTypeID IN 
(
    SELECT ResidentialComponentTypes.ResidentialComponentTypeID AS ResidentialComponentTypeId 
    FROM 
     ResidentialComponentTypes INNER JOIN ResidentialComponentValues 
     ON ResidentialComponentTypes.ResidentialComponentTypeID=ResidentialComponentValues.ResidentialComponentTypeID 
     INNER JOIN 
     (
      SELECT DISTINCT 
       ResidentialComponentValues.ResidentialComponentTypeID AS ResidentialComponentTypeId, 
       MAX(ResidentialComponentValues.EffectiveDate) AS EffectiveDate 
      FROM ResidentialComponentValues 
      WHERE ResidentialComponentValues.EffectiveDate <= '2012-01-03 00:00:00:000' 
      GROUP BY ResidentialComponentValues.ResidentialComponentTypeID 
     ) LPA_E1 
     ON 
      LPA_E1.ResidentialComponentTypeId = ResidentialComponentValues.ResidentialComponentTypeID 
      AND LPA_E1.EffectiveDate = ResidentialComponentValues.EffectiveDate 
) 

편집 :

/****** Object: Table [dbo].[ResidentialComponentTypes] Script Date: 01/03/2012 13:49:06 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
SET ANSI_PADDING ON 
GO 
CREATE TABLE [dbo].[ResidentialComponentTypes](
    [ResidentialComponentTypeID] [int] IDENTITY(1,1) NOT NULL, 
    [ComponentTypeName] [varchar](255) NOT NULL, 
    [LastUpdated] [datetime] NOT NULL, 
    [LastUpdatedBy] [varchar](50) NOT NULL, 
    [ConcurrencyTimestamp] [timestamp] NOT NULL, 
    [Active] [bit] NOT NULL, 
CONSTRAINT [PK_ResidentialComponentTypes] PRIMARY KEY CLUSTERED 
(
    [ResidentialComponentTypeID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 
SET ANSI_PADDING OFF 
GO 
/****** Object: Table [dbo].[ResidentialComponentValues] Script Date: 01/03/2012 13:49:06 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
SET ANSI_PADDING ON 
GO 
CREATE TABLE [dbo].[ResidentialComponentValues](
    [ResidentialComponentValueID] [int] IDENTITY(1,1) NOT NULL, 
    [ResidentialComponentTypeID] [int] NOT NULL, 
    [Value] [decimal](18, 3) NOT NULL, 
    [Story] [varchar](255) NOT NULL, 
    [LastUpdated] [datetime] NOT NULL, 
    [LastUpdatedBy] [varchar](50) NOT NULL, 
    [ConcurrencyTimestamp] [timestamp] NOT NULL, 
    [EffectiveDate] [datetime] NOT NULL, 
    [DefaultQuantity] [int] NOT NULL, 
CONSTRAINT [PK_ResidentialComponentPrices] PRIMARY KEY CLUSTERED 
(
    [ResidentialComponentValueID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 
SET ANSI_PADDING OFF 
GO 
CREATE NONCLUSTERED INDEX [_dta_index_ResidentialComponentValues_71_56543435__K1] ON [dbo].[ResidentialComponentValues] 
(
    [ResidentialComponentValueID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 
CREATE NONCLUSTERED INDEX [_dta_index_ResidentialComponentValues_71_56543435__K1_2_3_4_5_6_7_8_9] ON [dbo].[ResidentialComponentValues] 
(
    [ResidentialComponentValueID] ASC 
) 
INCLUDE ([ResidentialComponentTypeID], 
[Value], 
[Story], 
[LastUpdated], 
[LastUpdatedBy], 
[ConcurrencyTimestamp], 
[EffectiveDate], 
[DefaultQuantity]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 
CREATE NONCLUSTERED INDEX [_dta_index_ResidentialComponentValues_71_56543435__K2_K1] ON [dbo].[ResidentialComponentValues] 
(
    [ResidentialComponentTypeID] ASC, 
    [ResidentialComponentValueID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 
CREATE NONCLUSTERED INDEX [_dta_index_ResidentialComponentValues_71_56543435__K2_K8_K1] ON [dbo].[ResidentialComponentValues] 
(
    [ResidentialComponentTypeID] ASC, 
    [EffectiveDate] ASC, 
    [ResidentialComponentValueID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 
CREATE NONCLUSTERED INDEX [_dta_index_ResidentialComponentValues_71_56543435__K2_K8_K1_3_4_5_6_7_9] ON [dbo].[ResidentialComponentValues] 
(
    [ResidentialComponentTypeID] ASC, 
    [EffectiveDate] ASC, 
    [ResidentialComponentValueID] ASC 
) 
INCLUDE ([Value], 
[Story], 
[LastUpdated], 
[LastUpdatedBy], 
[ConcurrencyTimestamp], 
[DefaultQuantity]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
GO 
/****** Object: ForeignKey [FK_ResidentialComponentValues_ResidentialComponentTypes] Script Date: 01/03/2012 13:49:06 ******/ 
ALTER TABLE [dbo].[ResidentialComponentValues] WITH CHECK ADD CONSTRAINT [FK_ResidentialComponentValues_ResidentialComponentTypes] FOREIGN KEY([ResidentialComponentTypeID]) 
REFERENCES [dbo].[ResidentialComponentTypes] ([ResidentialComponentTypeID]) 
GO 
ALTER TABLE [dbo].[ResidentialComponentValues] CHECK CONSTRAINT [FK_ResidentialComponentValues_ResidentialComponentTypes] 
GO 

enter image description here

+1

내가 당신이 말한 알고 기록 2와 4를 반환 이것은 단순화되었지만 내부 쿼리와 외부 쿼리 사이에 중복 별칭이있을 수 있습니다. 그렇게하면 엔진이 훨씬 느린 상관 관계가있는 하위 쿼리로이를 수행하려고 할 수 있습니다. – JNK

+0

별칭이 없지만 테이블 이름을 직접 참조하는 것이 동일한 작업을 수행하는 것일 수 있습니다. 하위 쿼리의 Table1에 별칭을 추가해보고 도움이되는지 확인해 보겠습니다. – Dan

+0

@JNK - 이것은 * scope *의 모든 규칙을 어기는 것이지, 이것이 정말로 문제라고 상상할 수는 없습니다. – MatBailie

답변

0

당신이 실제로 달성하고자하는 것을 당신의 질문을 읽는 것이 분명하지 않습니다. 외부 쿼리가 각 ResidentialComponentType에 대해 가장 최근에 유효한 ResidentialComponentValues ​​레코드 만 선택하려고합니까?

가장 안쪽에있는 쿼리의 DISTINCT은 불필요한 것으로 보이며 쿼리를 최적화하는 데 약간의 어려움이있을 수 있습니다.2 열만 선택하고 하나씩 그룹화하고 다른 열을 집계하므로 결과가 이미 분명 할 것입니다. 아마도 쿼리 최적화 도구가 무시할지라도 DISTINCT을 지정하여 데이터베이스가이 쿼리를보다 효율적으로 실행할 수 있도록 지원하지 않습니다.

마찬가지로 내부 쿼리의 ResidentialComponentValues에 대한 첫 번째 INNER JOIN은 불필요한 것처럼 보입니다.

하위 쿼리 (아래 표시)에있는 INNER JOIN의 두 번째 조건은 나를 혼란스럽게합니다. 이것은 단순히 LPA_E1 결과를 하위 쿼리의 첫 번째 INNER JOIN의 ResidentialComponentValues ​​테이블에 합치는 것처럼 보이지만 실제로하려는 것은 외부 쿼리의 ResidentialComponentValues ​​테이블과 조인하는 것입니다.

ON 
    LPA_E1.ResidentialComponentTypeId = ResidentialComponentValues.ResidentialComponentTypeID 
    AND LPA_E1.EffectiveDate = ResidentialComponentValues.EffectiveDate 

내 생각 엔 내가 당신의 원본과 동일한 결과를 생각하지 않습니다하지만 아래, 당신이 정말로 원하는 쿼리 것입니다. 이렇게하면 각 ResidentialComponentType에 대한 가장 최근의 유효한 ResidentialComponentValue 레코드 만 선택됩니다.

declare @endDate datetime 
set @endDate = '2012-01-03 00:00:00:000' 

SELECT 
    ResidentialComponentValues.ResidentialComponentValueID AS ResidentialComponentValueId, 
    ResidentialComponentValues.ResidentialComponentTypeID AS ResidentialComponentTypeId, 
    ResidentialComponentValues.Value, 
    ResidentialComponentValues.Story, 
    ResidentialComponentValues.LastUpdated, 
    ResidentialComponentValues.LastUpdatedBy, 
    ResidentialComponentValues.ConcurrencyTimestamp, 
    ResidentialComponentValues.EffectiveDate, 
    ResidentialComponentValues.DefaultQuantity 
FROM 
    ResidentialComponentValues 
WHERE 
    -- the effective date for this ResidentialComponentValue record has already passed 
    ResidentialComponentValues.EffectiveDate <= @endDate 
    -- and there does not exist any other ResidentialComponentValue record for the same ResidentialComponentType that is effective more recently 
    and not exists (
     select 1 
     from ResidentialComponentValues LPA_E1 
     where 
      LPA_E1.ResidentialComponentTypeID = ResidentialComponentValues.ResidentialComponentTypeID 
      and LPA_E1.EffectiveDate <= @endDate 
      and LPA_E1.EffectiveDate > ResidentialComponentValues.EffectiveDate 
    ) 

사이드 참고 : 내 생각 엔이 쿼리는 열 (ResidentialComponentTypeID, EFFECTIVEDATE)에 대한 ResidentialComponentValues ​​테이블에 2 열 인덱스에서 도움이 될 것입니다.


또한 아래에 표시된이 쿼리는 원본과 동일한 결과를 나타낼 것이라고 생각합니다. 내 생각에 빠른 실행이 될 것입니다.

SELECT 
    ResidentialComponentValues.ResidentialComponentValueID AS ResidentialComponentValueId, 
    ResidentialComponentValues.ResidentialComponentTypeID AS ResidentialComponentTypeId, 
    ResidentialComponentValues.Value, 
    ResidentialComponentValues.Story, 
    ResidentialComponentValues.LastUpdated, 
    ResidentialComponentValues.LastUpdatedBy, 
    ResidentialComponentValues.ConcurrencyTimestamp, 
    ResidentialComponentValues.EffectiveDate, 
    ResidentialComponentValues.DefaultQuantity 
FROM 
    ResidentialComponentValues 
WHERE 
    -- show any ResidentialComponentValue records where there is any other currently effective ResidentialComponentValue record for the same ResidentialComponentType 
    exists (
     select 1 
     from ResidentialComponentValues LPA_E1 
     where 
      LPA_E1.ResidentialComponentTypeID = ResidentialComponentValues.ResidentialComponentTypeID 
      and LPA_E1.EffectiveDate <= @endDate 
    ) 


는 다음의 시험 데이터를 감안할 때, 첫 번째 쿼리는 두 번째 쿼리가 기록 1, 2, 3, 4를 반환하고, 5

insert into ResidentialComponentTypes values (1) 
insert into ResidentialComponentTypes values (2) 
insert into ResidentialComponentTypes values (3) 

insert into ResidentialComponentValues (ResidentialComponentValueID, ResidentialComponentTypeID, Value, Story, LastUpdated, LastUpdatedBy, EffectiveDate, DefaultQuantity) 
      select 1, 1, 'One', 'Blah', getdate(), 'Blah', '2012-01-01', 1 
union all select 2, 1, 'Two', 'Blah', getdate(), 'Blah', '2012-01-02', 1 
union all select 3, 1, 'Three', 'Blah', getdate(), 'Blah', '2012-01-04', 1 
union all select 4, 2, 'Four', 'Blah', getdate(), 'Blah', '2012-01-02', 1 
union all select 5, 2, 'Five', 'Blah', getdate(), 'Blah', '2012-01-04', 1 
union all select 6, 3, 'Six', 'Blah', getdate(), 'Blah', '2012-01-04', 1 
+0

귀하의 질의를 살펴보고 같은 일을하는지 확인할 수 있는지 확인하겠습니다. 달성하고자하는 것은 해당 ResidentialComponentType에 대한 가장 최근의 발효 일을 가진 각 ResidentialComponentType에 대한 모든 ResidentialComponentValues를 얻는 것입니다.이 작업을한지 꽤 오래되었지만 쿼리의 일부가 ResidentialComponentType이 해당 날짜에 유효했는지 확인 중이라고 생각합니다. 다시 말해, 나는 그 날짜 이후에 만들어진 것들을 원하지 않는다. – Dan

+0

@ Dan - 감사합니다. 나는 * 내 대답에있는 첫 번째 SELECT 쿼리가 당신이 무엇을 제공한다고 생각한다. 각 ResidentialComponentType에 대해 가장 최근에 유효한 ResidentialComponentValues를 가져 오되 지정된 날짜 이후에만 유효한 값은 제외하십시오. –

+0

그는 이미'(ResidentialComponentTypeID, EffectiveDate)'에 대한 색인을 가지고 있습니다. –

0

내부 하위 쿼리로 DISTINCT이 필요하지 않습니다 당신이 이미 GROUP BY ResidentialComponentTypeID :

(
     SELECT DISTINCT 
      ResidentialComponentValues.ResidentialComponentTypeID 
       AS ResidentialComponentTypeId, 
      MAX(ResidentialComponentValues.EffectiveDate) 
       AS EffectiveDate 
     FROM ResidentialComponentValues 
     WHERE ResidentialComponentValues.EffectiveDate 
       <= '2012-01-03 00:00:00:000' 
     GROUP BY ResidentialComponentValues.ResidentialComponentTypeID 
    ) LPA_E1 
SQL-Server가이 문제를 인식하고 최적화하지만 확실하게 다시 작성할 수 있습니다 않을 경우 17,451,515,

확실하지 :

내가 잘못 아니에요 경우

이 그리고, 당신은 또한 필요

(
     SELECT 
      rcv.ResidentialComponentTypeID 
      MAX(rcv.EffectiveDate) AS EffectiveDate 
     FROM ResidentialComponentValues AS rcv 
     WHERE rcv.EffectiveDate 
       <= '2012-01-03 00:00:00:000' 
     GROUP BY rcv.ResidentialComponentTypeID 
    ) LPA_E1 
도 쿼리의 다른 DISTINCT도 여분의 하위 쿼리 중첩. 거기에 ResidentialComponentValues에서 Foreign Key 제약이 있지만, 아마도 당신이 다른에 사용되는 가입 한 것과 같은

SELECT 
    v.ResidentialComponentValueID, 
    v.ResidentialComponentTypeID, 
    v.Value, 
    v.Story, 
    v.LastUpdated, 
    v.LastUpdatedBy, 
    v.ConcurrencyTimestamp, 
    v.EffectiveDate, 
    v.DefaultQuantity 
FROM 
     ResidentialComponentTypes AS t 
    INNER JOIN ResidentialComponentValues AS v 
     ON t.ResidentialComponentTypeID=v.ResidentialComponentTypeID 
    INNER JOIN 
     (
      SELECT 
       rcv.ResidentialComponentTypeID 
       MAX(rcv.EffectiveDate) AS EffectiveDate 
      FROM ResidentialComponentValues AS rcv 
      WHERE rcv.EffectiveDate 
        <= '2012-01-03 00:00:00:000' 
      GROUP BY rcv.ResidentialComponentTypeID 
     ) LPA_E1 
     ON 
      LPA_E1.ResidentialComponentTypeId = v.ResidentialComponentTypeID 
      AND LPA_E1.EffectiveDate = v.EffectiveDate 

당신은 또한 ResidentialComponentTypes에 가입 할 필요가 없습니다 :이 재 작성이 같은 결과를 얻을 수 있는지 확인 보고서.


이이 LLBL에서 수행 될 수 있지만, 당신은 생성 된 코드에서 DISTINCT 중 하나를 제거 할 수 있는지 방법을 모르고 - 특히 첫 번째 - 또는 여분의 중첩 (또는 추가 가입), 아마 도움이 될 것입니다 혼란 된 옵티마이 저.

+0

LLBL이 별개의 기능을 추가하고 있다고 생각하지만, 어떻게 든 추가하고 있는지 확인할 것입니다. 재 작성이 도움이 된 것처럼 보이지 않습니다. – Dan

+0

@ Dan : LLBL이 두 테이블 간의 관계를 어떻게 볼 수 있는지 확인할 수 있습니까? 그것은 '일대 다'입니까? –