표 값 함수 와 연결 하여 발생 하 는 성능 문제 분석

9588 단어 표 값 함수성능
표 값 함수
    SQL Server 에 서 는 다른 프로 그래 밍 언어 와 유사 한 함 수 를 제공 합 니 다.함수 의 본질은 보통 코드 의 패키지 이 고 값 을 되 돌려 줍 니 다.SQL Server 에서 함 수 는 간단 한 데이터 형식 외 에(Int,Varchar 등)집합 을 되 돌려 줄 수 있 습 니 다.즉,표를 되 돌려 주 는 것 입 니 다.
    그리고 집합 으로 직접 돌아 가 거나 정 의 된 후에 집합 으로 돌아 가 는 지 여부 에 따라 표 값 함 수 는 내 연 사용자 정의 표 값 함수 와 사용자 정의 표 값 함수 로 나 뉜 다.
내 연 표 값 함수
    내 연 표 값 함수 와 일반 함 수 는 다 르 지 않 습 니 다.유일한 차이 점 은 결 과 를 집합(표)으로 되 돌려 주 는 것 입 니 다.간단 한 데이터 형식 이 아니 라 간단 한 내 연 표 값 함수 입 니 다.코드 목록 1 과 같은 간단 한 내 연 표 값 함수(MSDN 에서 발췌)입 니 다.

CREATE FUNCTION Sales.ufn_CustomerNamesInRegion
( @Region nvarchar(50) )
RETURNS table
AS
RETURN (
SELECT DISTINCT s.Name AS Store, a.City
FROM Sales.Store AS s
INNER JOIN Person.BusinessEntityAddress AS bea 
ON bea.BusinessEntityID = s.BusinessEntityID 
INNER JOIN Person.Address AS a 
ON a.AddressID = bea.AddressID
INNER JOIN Person.StateProvince AS sp 
ON sp.StateProvinceID = a.StateProvinceID
WHERE sp.Name = @Region
);
GO
코드 목록 1.간단 한 표 값 함수
사용자 정의 표 값 함수
한편,사용자 정의 표 값 함 수 는 함수 가 시 작 될 때 되 돌아 오 는 표 구 조 를 정의 한 다음 에 모든 코드 를 써 서 데이터 조작 을 할 수 있 고 정 의 된 표 구조 에 삽입 한 후에 되 돌아 갈 수 있 습 니 다.코드 목록 2 와 같은 조금 담당 하 는 사용자 정의 표 값 함수 예제(MSDN 에서 따 옴).

CREATE FUNCTION dbo.ufnGetContactInformation(@ContactID int) 
RETURNS @retContactInformation TABLE 
( 
-- Columns returned by the function 
ContactID int PRIMARY KEY NOT NULL, 
FirstName nvarchar(50) NULL, 
LastName nvarchar(50) NULL, 
JobTitle nvarchar(50) NULL, 
ContactType nvarchar(50) NULL 
) 
AS 
-- Returns the first name, last name, job title, and contact type for the specified contact. 
BEGIN 
DECLARE 
@FirstName nvarchar(50), 
@LastName nvarchar(50), 
@JobTitle nvarchar(50), 
@ContactType nvarchar(50); 
-- Get common contact information 
SELECT 
@ContactID = BusinessEntityID, 
@FirstName = FirstName, 
@LastName = LastName 
FROM Person.Person 
WHERE BusinessEntityID = @ContactID; 
-- Get contact job title 
SELECT @JobTitle = 
CASE 
-- Check for employee 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'EM') 
THEN (SELECT JobTitle 
FROM HumanResources.Employee AS e 
WHERE e.BusinessEntityID = @ContactID) 
-- Check for vendor 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'VC') 
THEN (SELECT ct.Name 
FROM Person.ContactType AS ct 
INNER JOIN Person.BusinessEntityContact AS bec 
ON bec.ContactTypeID = ct.ContactTypeID 
WHERE bec.PersonID = @ContactID) 
 
-- Check for store 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'SC') 
THEN (SELECT ct.Name 
FROM Person.ContactType AS ct 
INNER JOIN Person.BusinessEntityContact AS bec 
ON bec.ContactTypeID = ct.ContactTypeID 
WHERE bec.PersonID = @ContactID) 
ELSE NULL 
END; 
-- Get contact type 
SET @ContactType = 
CASE 
-- Check for employee 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'EM') 
THEN 'Employee' 
-- Check for vendor 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'VC') 
THEN 'Vendor Contact' 
-- Check for store 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'SC') 
THEN 'Store Contact' 
-- Check for individual consumer 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'IN') 
THEN 'Consumer' 
-- Check for general contact 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'GC') 
THEN 'General Contact' 
END; 
-- Return the information to the caller 
IF @ContactID IS NOT NULL 
BEGIN 
INSERT @retContactInformation 
SELECT @ContactID, @FirstName, @LastName, @JobTitle, @ContactType; 
END; 
RETURN; 
END; 
GO
코드 주문 2.표 값 함수
왜 표 값 함 수 를 사용 합 니까?
    표 값 함수 가 하 는 일과 저장 과정 은 다 르 지 않 은 것 같 지만 실제로는 차이 가 있다.표 값 함수 가 다른 조회 에 쓸 수 있 기 때문에 저장 과정 이 안 됩 니 다.이 밖 에 표 값 함수 와 Apply 연산 자 를 결합 하여 사용 하면 연결 작업 을 크게 간소화 할 수 있 습 니 다.
    저장 과정 이 다음 조건 중 하나 에 부합 한다 면 표 값 함수 로 재 작성 하 는 것 을 고려 할 수 있 습 니 다.
•저장 프로 세 스 논 리 는 매우 간단 합 니 다.단지 하나의 Select 구문 일 뿐 보기 가 필요 하지 않 은 이 유 는 매개 변수 가 필요 하기 때 문 입 니 다.
•저장 과정 에서 업데이트 작업 이 없습니다.
•저장 과정 에서 동적 SQL 이 없습니다.
•저장 과정 에서 결과 집합 만 되 돌려 줍 니 다.
•저장 과정의 주요 목적 은 임시 결과 집합 을 만 들 고 결과 집합 을 임시 표 에 저장 하여 다른 조회 호출 을 제공 하 는 것 입 니 다.
질문
    표 값 함 수 는 내 연 표 값 함수 와 달리 내 연 표 값 함 수 는 처리 하 는 과정 에서 하나의 보기 와 같 습 니 다.이것 은 조회 최적화 단계 에서 내 연 표 값 함수 가 조회 최적화 기 에 참여 할 수 있다 는 것 을 의미 합 니 다.예 를 들 어 선별 조건(Where)을 대수 트 리 의 밑부분 으로 미 룰 수 있 습 니 다.이것 은 먼저 Where 에서 Join 할 수 있다 는 것 을 의미 합 니 다.색인 을 이용 하여 IO 를 낮 추어 성능 을 향상 시 킬 수 있 습 니 다.
    간단 한 예 를 보 자.다음 코드 예제 는 간단 한 표 값 함수 와 Join 을 만 드 는 예 입 니 다.
    우선,우 리 는 표 값 함 수 를 만 듭 니 다.각각 내 연 표 값 함수 방식 과 표 값 함수 방식 입 니 다.예 를 들 어 코드 목록 3 과 같 습 니 다.

--       
CREATE FUNCTION tvf_multi_Test ( ) 
RETURNS @SaleDetail TABLE ( ProductId INT ) 
AS 
BEGIN 
INSERT INTO @SaleDetail 
SELECT ProductID 
FROM Sales.SalesOrderHeader soh 
INNER JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID 
RETURN 
END 
--         
CREATE FUNCTION tvf_inline_Test ( ) 
RETURNS TABLE 
AS 
RETURN 
SELECT ProductID 
FROM Sales.SalesOrderHeader soh 
INNER JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID 
코드 목록 3.서로 다른 함수 만 들 기
현재,우 리 는 같은 조 회 를 사용 하여 이 두 표 값 함수 에 대해 Join 을 진행 합 니 다.코드 목록 4 와 같 습 니 다.

--     Join 
SELECT c.personid , 
Prod.Name , 
COUNT(*) 'numer of unit' 
FROM Person.BusinessEntityContact c 
INNER JOIN dbo.tvf_multi_Test() tst ON c.personid = tst.ProductId 
INNER JOIN Production.Product prod ON tst.ProductId = prod.ProductID 
GROUP BY c.personid , 
Prod.Name 
 
--       Join 
SELECT c.personid , 
Prod.Name , 
COUNT(*) 'numer of unit' 
FROM Person.BusinessEntityContact c 
INNER JOIN dbo.tvf_inline_Test() tst ON c.personid = tst.ProductId 
INNER JOIN Production.Product prod ON tst.ProductId = prod.ProductID 
GROUP BY c.personid , 
Prod.Name
코드 목록 4.표 값 함수 와 내 연 표 값 함수 가 Join 을 합 니 다.
집행 원 가 는 그림 1 과 같다.

그림 1.두 가지 방식 의 원가
IO 를 보면 차 우 를 선택 한 것 이 분명 하 다.비 즈 니스 엔 터 티 연락처 는 스 캔 이 아 닌 121317 번 을 선택 했다.내 연 표 함 수 는 한 번 검색 하 는 비용 이 한 번 검색 하 는 것 보다 훨씬 낮 다 는 것 을 정확하게 알 수 있다.
그 문제 의 근원 은 내 연 표 값 함수 입 니 다.SQL Server 에 있어 보기 와 같 습 니 다.이 는 내 연 표 값 함수 가 논리 적 으로 계획 을 수행 하 는 대수 연산(또는 대수 트 리 최적화)에 참여 할 수 있다 는 것 을 의미 합 니 다.이 는 내 축 표 가 더 나 눌 수 있다 는 것 을 의미 합 니 다(그림 1 참조,두 번 째 내 연 표 조회.실행 계획 은 내 축 표 에 SalesOrderHeader 표 와 SalesOrderDetail 표 가 있 음 을 구체 적 으로 알 고 있 습 니 다.조 회 는 한 열 만 선택 하기 때문에 실행 계획 은 SalesOrderHeader 표 를 스 캔 하지 않 아 도 될 때 까지 최적화 되 었 습 니 다).내 연 표 값 함수 에 있어 실행 계획 은 관련 표 의 색인 과 관련 통계 정보 등 메타 데 이 터 를 완전 하 게 알 수 있 습 니 다.
다른 한편,표 값 함 수 는 그림 1 의 첫 번 째 부분 에서 보 듯 이 표 값 함 수 는 전체 실행 계획 에 있어 블랙박스 이 고 통계 정보 도 모 르 며 색인 도 없다.실행 계획 에서 표 값 함수 와 관련 된 표(그림 1 에서\#AE4E 5168 이라는 임시 표 이지 구체 적 인 표시 가 아 닌)를 모 르 기 때문에 전체 실행 계획 에 있어 서 이 결과 집 SQL Server 는 되 돌아 오 는 결과 가 매우 작다 고 가정 하고 표 값 함수 가 되 돌아 오 는 결과 가 많 을 때(본 사례 에서 보 듯 이)비교적 나 쁜 실행 계획 이 생 길 수 있다.
따라서 다시 말 하면 표 값 함수 가 결 과 를 되 돌려 주 는 시간 은 성능 에 영향 을 주지 않 을 수 있 지만 결과 가 조금 많 으 면 실행 계획 의 질 에 영향 을 줄 수 있다.
어떻게 처리 합 니까?
우선,SQL Server 에서 저 장 된 값 함수 와 Join 이 되 는 문 구 를 찾 아야 합 니 다.실행 계획 을 발굴 함으로써 저 희 는 이러한 문 구 를 찾 을 수 있 습 니 다.코드 목록 5 와 같은 코드 를 사용 할 수 있 습 니 다.

WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) 
SELECT st.text, 
qp.query_plan 
FROM ( 
SELECT TOP 50 * 
FROM sys.dm_exec_query_stats 
ORDER BY total_worker_time DESC 
) AS qs 
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st 
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp 
WHERE qp.query_plan.exist('//p:RelOp[contains(@LogicalOp, "Join")]/*/p:RelOp[(@LogicalOp[.="Table-valued function"])]') = 1
코드 목록 5.실행 계획 캐 시 에서 표 값 함수 와 Join 의 조 회 를 찾 습 니 다.
결 과 는 그림 2 와 같다.

그림 2.계획 캐 시 에 존재 하 는 표 값 함수 와 Join 의 조 회 를 수행 합 니 다.
작은 매듭
본 고 는 표 값 함수 의 개념,표 값 함수 가 왜 성능 에 영향 을 미 치 는 지,그리고 실행 계획 캐 시 에서 표 값 함수 와 Join 의 조 회 를 하 는 지 논술 하 였 다.표 값 함수 와 apply 또는 표 값 함수 가 되 돌아 오 는 줄 수가 매우 작은 조회 에 영향 을 주지 않 을 수도 있 습 니 다.그러나 반환 결과 가 많은 표 값 함수 에 Join 을 하면 성능 문제 가 발생 할 수 있 으 므 로 가능 하 다 면 표 값 함 수 를 내 연 표 값 함수 로 다시 쓰 거나 표 값 함수 의 결 과 를 임시 표 에 저장 한 다음 Join 을 하면 성능 을 향상 시 킬 수 있 습 니 다.
참고 자료:
http://www.brentozar.com/blitzcache/tvf-join/
http://blogs.msdn.com/b/psssql/archive/2010/10/28/query-performance-and-multi-statement-table-valued-functions.aspx?CommentPosted=true#commentmessage

좋은 웹페이지 즐겨찾기