2014-02-06 2 views
1

DB gurus에 대해서는 SELECT 조인 결과와 이전에 채워진 테이블 변수에 조인간에 기능적/성능 차이가 있는지 궁금합니다. 저는 SQL Server 2008 R2에서 일하고 있습니다.SELECT에 조인 대 테이블 세트에 조인

예 (TSQL) : "진짜"세계에서

-- Create a test table 
DROP TABLE [dbo].[TestTable] 
CREATE TABLE [dbo].[TestTable](
    [id] [int] NOT NULL, 
    [value] [varchar](max) NULL 
) ON [PRIMARY] 
-- Populate the test table with a few rows 
INSERT INTO [dbo].[TestTable] 
SELECT 1123, 'test1' 

INSERT INTO [dbo].[TestTable] 
SELECT 2234, 'test2' 

INSERT INTO [dbo].[TestTable] 
SELECT 3345, 'test3' 

-- Create a reference table 
DROP TABLE [dbo].[TestRefTable] 
CREATE TABLE [dbo].[TestRefTable](
    [id] [int] NOT NULL, 
    [refvalue] [varchar](max) NULL 
) ON [PRIMARY] 
-- Populate the reference table with a few rows 
INSERT INTO [dbo].[TestRefTable] 
SELECT 1123, 'ref1' 

INSERT INTO [dbo].[TestRefTable] 
SELECT 2234, 'ref2' 

-- Scenario 1: Insert matching results into it's own table variable, then Join 

-- Create a table variable 
DECLARE @subset TABLE ([id] INT NOT NULL, [refvalue] VARCHAR(MAX)) 

INSERT INTO @subset 
SELECT * FROM [dbo].[TestRefTable] 
WHERE [dbo].[TestRefTable].[id] = 1123 

SELECT t.*, s.* 
FROM [dbo].[TestTable] t 
JOIN @subset s 
ON t.id = s.id 

-- Scenario 2: Join directly to SELECT results 
SELECT t.*, s.* 
FROM [dbo].TestTable t 
JOIN (SELECT * FROM [dbo].[TestRefTable] WHERE id = 1123) s 
ON t.id = s.id 

는 테이블과 테이블 변수는 사전 정의입니다. 내가 바라는 것은 추가 작업에 사용할 수있는 일치하는 참조 행을 가질 수 있지만 추가 단계로 인해 쿼리 속도가 느려지는 것이 걱정됩니다. 왜 다른 사람보다 더 빠른 이유가 기술적 인 이유가 있습니까? 두 가지 접근 방식간에 어떤 종류의 성능 차이가있을 수 있습니까? 확실한 대답을 내리는 것이 (불가능하지는 않더라도) 어렵다는 것을 알고 있습니다. 단지이 시나리오에 대한 조언을 구하는 것입니다.

+2

프로덕션 환경에서는 SELECT t. *, s. * 과 같은 코드를 사용하고 싶지 않습니다. Seect * i는 SQl antipatattern과 같은 조인이있을 때 jon fileds에 동일한 데이터가 포함되어 있기 때문에 필요없는 필드를 트 레터링합니다. 이것은 매우 가난한 실천입니다. 필요 이상으로 더 많은 데이터를 반환하지 마십시오. – HLGEM

+0

이것은 훌륭한 질문이며 훌륭한 답변입니다. 나는 아마 "나, 너무"논평을위한 물갈퀴를 얻을 것이다, 그러나 +1은 충분하지 않았습니다. –

답변

2

데이터베이스 엔진에는 쿼리를 실행하는 가장 좋은 방법을 파악할 수있는 최적화 프로그램이 있습니다. 당신이 상상할 수있는 것보다 더 많은 것들이 있습니다. SQL Server가 가입하고있는 경우 예를 들어, 적어도 네 개의 알고리즘 가입을 선택할 수있다 :이

  • 인덱스 조회는
  • 병합 가입
  • 해시 가입

    • 중첩 루프를

    (이들의 멀티 스레드 버전은 말할 것도 없습니다.)

    이들 각각의 작동 방식을 이해하는 것은 중요하지 않습니다. 두 가지를 이해하면됩니다. 서로 다른 알고리즘이 서로 다른 상황에서 가장 좋으며 SQL Server는 최상의 알고리즘을 선택하기 위해 최선을 다합니다.

    조인 알고리즘의 선택은 옵티마이 저가 수행하는 것 중 하나입니다. 또한 조인의 순서, 결과를 집계하는 가장 좋은 방법, 정렬이 order by에 필요한지 여부, 인덱스 또는 직접 통해 데이터에 액세스하는 방법 등을 알아야합니다.

    쿼리를 분리하면 최적화에 대한 가정이 생깁니다.귀하의 경우, 가장 좋은 것은 특정 테이블에 대한 선택을 수행한다는 것입니다. 당신이 옳을 수도 있습니다. 그렇다면 여러 쿼리를 사용한 결과는 단일 쿼리를 사용하는 것보다 빠릅니다. 음, 그렇지 않을 수도 있습니다. 단일 쿼리에서 SQL Server는 모든 결과를 한 번에 버퍼링 할 필요가 없습니다. 결과를 한 곳에서 다른 곳으로 스트리밍 할 수 있습니다. 또한 쿼리를 분리하는 방식으로 병렬 처리를 활용할 수도 있습니다.

    일반적으로 SQL Server 최적화 프로그램은 매우 유용하므로 최적화 프로그램이 쿼리를 한 번에 처리하도록하는 것이 가장 좋습니다. 최적화 프로그램이 최적의 실행 경로를 선택하지 못할 수있는 예외가 있습니다. 경우에 따라 통계를 최신 상태로 유지하는 것이 쉽습니다. 다른 때에는 옵티 마이저 힌트를 추가 할 수 있습니다. 그리고 다른 방법으로는 쿼리를 다시 구성 할 수 있습니다.

    예를 들어 로컬 테이블에 데이터를로드하는 것이 유용한 한 가지 경우는 다른 서버에서 테이블을 가져 오는 경우입니다. 최적화 알고리즘은 최상의 결정을 내리기 위해 테이블 ​​크기에 대한 완전한 정보를 가지고 있지 않을 수도 있습니다.

    즉, 쿼리를 하나의 명령문으로 유지하십시오. 그것을 개선 할 필요가 있다면, 그것이 작동 한 후에 최적화에 집중하십시오. 당신은 일반적으로 최적화에 많은 시간을 할애 할 필요가 없을 것입니다.

  • 2

    이렇게하면 같은 결과가 나타 납니까?

    SELECT t.*, s.* 
    FROM dbo.TestTable AS t 
    JOIN dbo.TestRefTable AS s ON t.id = s.id AND s.id = 1123 
    

    기본적으로,이 십자가는 id = 1123TestTableTestRefTable에서 모든 레코드의 결합이다.

    +0

    당신은 나머지 성명서를 무시하고 교차 결합을 만들었습니다. – HLGEM

    +0

    @HLGEM OP는 기본적으로 여기에 교차 결합을 요구하고 있습니다. 비록 내 대답을 조금 분명히했습니다. – Aquillo

    +0

    그래서이 접근 방식은 SELECT의 결과에 합류하는 것이 더 효율적입니까? 아니면 두 가지 모두에 대해 동일하게 최적화됩니까? – Jason

    0

    직접 테이블 조인이 TableVariable 테이블보다 빠르며 리소스를 덜 사용하길 기대합니다.

    1

    일반적으로 쿼리의 파생 테이블은 인덱스를 사용할 수 있고 테이블 변수에서 사용할 수 없기 때문에 테이블 변수에 조인하는 것보다 빠를 것입니다. 그러나 임시 테이블에는 인덱스가 생겨 잠재적 인 성능 차이가 해결 될 수도 있습니다.

    또한 테이블 변수 레코드의 수가 작을 것으로 예상되는 경우 인덱스가 큰 차이를 만들지 않으므로 차이가 거의 없거나 없습니다.

    alawys는 자신의 시스템에서 레코드 수와 테이블 디자인 및 인덱스 디자인이 가장 잘 작동하는 것과 관련하여 테스트해야합니다.

    2

    테이블 변수에 조인하면 최적화 프로그램에서 카디널리티가 잘못 계산됩니다. 테이블 변수는 항상 단일 행만 포함하도록 옵티마이 저가 가정합니다. 행이 많을수록 추정치가 나빠집니다. 이로 인해 옵티마이 저가 테이블 자체에 대해 잘못된 행 수를 가정하게되지만 다른 위치에서는 그 결과에 조인 할 수있는 연산자에 대해 해당 연산의 번호 실행에 대한 잘못된 예측이 발생할 수 있습니다.

    개인적으로 테이블 매개 변수는 클라이언트 응용 프로그램 (C# .Net 응용 프로그램이이를 잘 활용 함)을 사용하거나 저장 프로 시저간에 데이터를 전달할 때 편리하게 서버를오고가는 데 사용되어야한다고 생각하지만 사용해서는 안됩니다 proc 자체 내에서 너무 많이. Proc 코드 자체에서 이들을 제거하는 중요성은 매개 변수에 의해 운반 될 예상 행 수와 함께 증가합니다.

    하위 선택이 더 잘 수행되거나 즉시 임시 테이블에 복사하면 제대로 작동합니다. 임시 테이블에 복사하기위한 오버 헤드가 있지만 옵티마이 저가 예상치가 나빠질수록 오버 헤드가 발생하는 행이 많을수록 더 많은 행을 가질 수 있습니다.