블로그 이미지
010-9967-0955 보미아빠

카테고리

보미아빠, 석이 (500)
밥벌이 (16)
싸이클 (1)
일상 (1)
Total
Today
Yesterday

달력

« » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

공지사항

최근에 올라온 글

http://technet.microsoft.com/en-us/library/ms144262.aspx

Posted by 보미아빠
, |

아래 테스트는 ISV 에서 만든 어플리케이션과 같이 특수한 환경에서 쿼리를 직접 고치지 못할 때 유용한 쿼리 힌트 방법이다. 특히 AD-HOC 쿼리로 들어오는 쿼리를 OPTIMIZE FOR 등의 방법으로 쿼리 힌트를 구현하고자 할 때 매우 유용한 방법이다. 스터디에서 OPTIMIZE FOR 의 설명은 많이 했으므로, 해당 설명은 생략 하도록 하겠다.

 

아래 내용은 편집해서 출판 할 것이므로, 그전에 오류나 추가할 내용 가이드 주세요~ ^.^

 

 

 

plan_guide_test.sql

 

12년 12월 11일 update

USE MASTER

GO

 

IF EXISTS (SELECT * FROM SYS.DATABASES WHERE NAME ='DB_PLAN_GUIDE_TEST')

BEGIN

       ALTER DATABASE  DB_PLAN_GUIDE_TEST SET SINGLE_USER WITH ROLLBACK IMMEDIATE

       DROP DATABASE DB_PLAN_GUIDE_TEST

END

GO

 

CREATE DATABASE DB_PLAN_GUIDE_TEST

 CONTAINMENT = NONE

 ON  PRIMARY

( NAME = N'DB_PLAN_GUIDE_TEST', FILENAME = N'L:\MSSQL\DB_PLAN_GUIDE_TEST.MDF' , SIZE = 100MB , MAXSIZE = UNLIMITED, FILEGROWTH = 100MB )

 LOG ON

( NAME = N'DB_PLAN_GUIDE_TEST_LOG', FILENAME = N'L:\MSSQL\DB_PLAN_GUIDE_TEST_LOG.LDF' , SIZE = 100MB , MAXSIZE = 2048GB , FILEGROWTH = 100MB )

GO

 

USE DB_PLAN_GUIDE_TEST

GO

 

-- 기본 상태로 만든다.

ALTER DATABASE DB_PLAN_GUIDE_TEST SET PARAMETERIZATION SIMPLE

GO

 

SELECT * FROM SYS.plan_guides

GO

 

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST1')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST1

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST2')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST2

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST3')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST3

GO

 

IF OBJECT_ID ('TBLX') IS NOT NULL

DROP TABLE TBLX

GO

 

WITH TEMP AS

(

SELECT TOP 1000000

          CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS INT) IDX

        , 'PNAME_'+RIGHT(REPLICATE('0',7)+CAST(CAST(ABS(CHECKSUM(NEWID())) % 1000 AS INT) AS VARCHAR(10)),7)+CHAR(ASCII('A') + ABS(CHECKSUM(NEWID()))%10) PRODUCTNAME

  FROM SYS.OBJECTS A1

 CROSS JOIN SYS.OBJECTS A2

 CROSS JOIN SYS.OBJECTS A3

 CROSS JOIN SYS.OBJECTS A4

 CROSS JOIN SYS.OBJECTS A5

)

SELECT IDX, PRODUCTNAME, CAST(SUBSTRING(PRODUCTNAME,7,7) AS INT) PRODUCTID

        , CAST(ABS(CHECKSUM(NEWID())) % 100 AS INT) SHOPID

        , CAST(ABS(CHECKSUM(NEWID())) % 1000000 AS INT) PRICE

        , DATEADD(MINUTE, CAST(ABS(CHECKSUM(NEWID())) % 20000 AS INT) * -1, GETDATE()) INSERTTIME

  INTO TBLX

  FROM TEMP

GO

 

--SELECT COUNT(*) FROM TBLX

--SELECT TOP 10 * FROM TBLX

 

CREATE UNIQUE CLUSTERED INDEX UCL_TBLX ON TBLX (IDX)

CREATE NONCLUSTERED INDEX NC_TBLX_02 ON TBLX (PRODUCTID)

GO

 

DBCC FREEPROCCACHE

GO

 

SET STATISTICS PROFILE ON

GO

 

-- SIMPLE PARAMETERIZATION 방지하기 위해 JOIN

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

-- SERIAL PLAN

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

-- PARALLEL PLAN

 

SET STATISTICS PROFILE OFF

 

-- 이제 항상 PARALLEISM 으로 동작 시키기 위해서 PLAN 고정시켜 보고자 한다.

-- QUERY A START

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

-- 확인을 위한 쿼리

SELECT @STMT, @PARAMS

 

EXEC SP_CREATE_PLAN_GUIDE

@NAME = N'PLAN_GUIDE_TEST1',

@STMT = @STMT,

@TYPE = N'SQL',

@MODULE_OR_BATCH = NULL,

@PARAMS = @PARAMS,

@HINTS = N'OPTION (OPTIMIZE FOR (@0 = 1000000))'

-- QUERY A END

 

SELECT * FROM SYS.plan_guides WHERE NAME = 'PLAN_GUIDE_TEST1'

 

-- 이렇게 해서는 PLAN_GUIDE 동작하지 않는다.

-- 왜냐구? 파라미터된 계획과 그렇지 않는 계획은 다른것 이기 때문이다.

 

-- 아래 쿼리가 PARALLEL 돌아야 하는데 SERIAL 동작한다.

-- 속성에도 PLAN GUIDE 쓰지 않은 것으로 뜬다.

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1

-- SERIAL PLAN 으로 동작함

 

-- 옵셥 확인

SELECT CASE WHEN IS_PARAMETERIZATION_FORCED = 0 THEN 'DISABLED' ELSE 'ENABLED' END

     , COMPATIBILITY_LEVEL

  FROM SYS.DATABASES

 WHERE NAME ='DB_PLAN_GUIDE_TEST'

GO

 

 

-- 강제 PARAMETERIZATION 활성화

ALTER DATABASE DB_PLAN_GUIDE_TEST SET PARAMETERIZATION FORCED

GO

 

-- 이제는 플랜가이드가 동작한다.

 

-- 기타 체크

-- 호환성 레벨 확인법

--exec sp_helpdb paging

--exec sp_dbcmptlevel paging

 

-- 호환성 레벨 변경방법

--ALTER DATABASE DB_PLAN_GUIDE_TEST

--SET COMPATIBILITY_LEVEL = 110

 

-- 호환성 레벨이 90 이상이고 IS_PARAMETERIZATION_FORCED 1 이면 가능하다.

 

DBCC FREEPROCCACHE

GO

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

-- 병렬실행 계획이 동작한다면 정상이다.

 

-- 하나의 쿼리를 파라미터화 해서 쓰기 위해 전체 데이터베이스 옵션을 변경 수는 없다.

-- 그래서 다시 SIMPLE 돌린다.

 

ALTER DATABASE DB_PLAN_GUIDE_TEST SET PARAMETERIZATION SIMPLE

GO

 

DBCC FREEPROCCACHE

GO

 

-- 해당 쿼리만 PARAMETERIZATION FORCED 옵션을 만들어주는 플랜가이드를 하나 만든다.

-- 기발한 생각이죠?

 

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

EXEC sp_create_plan_guide

    N'PLAN_GUIDE_TEST2',

    @stmt,

    N'TEMPLATE',

    NULL,

    @params,

    N'OPTION(PARAMETERIZATION FORCED)';

GO

 

-- 아래와 같이 두개의 플랜가이드를 확인한다.

SELECT * FROM SYS.plan_guides

GO

plan_guide_id name   create_date  modify_date  is_disabled  query_text   scope_type       scope_type_desc     scope_object_id     scope_batch  parameters   hints

65537  PLAN_GUIDE_TEST1    2012-12-08 21:27:21.103    2012-12-08 21:27:21.103    0      select SUM ( A . SHOPID ) from TBLX A join TBLX B on A . IDX = B . IDX where B . PRODUCTID < @0       2      SQL    NULL   select SUM ( A . SHOPID ) from TBLX A join TBLX B on A . IDX = B . IDX where B . PRODUCTID < @0     @0 int OPTION (OPTIMIZE FOR (@0 = 1000000))

65539  PLAN_GUIDE_TEST2    2012-12-08 23:31:13.657    2012-12-08 23:31:13.657    0      select SUM ( A . SHOPID ) from TBLX A join TBLX B on A . IDX = B . IDX where B . PRODUCTID < @0       3      TEMPLATE     NULL   select SUM ( A . SHOPID ) from TBLX A join TBLX B on A . IDX = B . IDX where B . PRODUCTID < @0      @0 int OPTION(PARAMETERIZATION FORCED)

-- 결국 두개의 PLAN_GUIDE 조합으로 PARAMETERIZATION SIMPLE 인데도 쿼리는 파라미터화 해서 동작 시킬 있다.

 

-- 아래 쿼리를 동작시키면 병렬로 동작 것이다.

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

 

-- 일반적인 테스트

-- 원상복귀

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST1')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST1

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST2')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST2

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST3')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST3

GO

-- 동작의 검증

--PROFILER 에서 PERFORMANCE > PLAN GUIDE SUCCESSFUL , PLAN GUIDE UNSUCCESSFUL 확인 가능하다.

--GRAPHIC 실행계획의 마지막 이터레이터에서 속성을 확인하면 플랜가이드가 사용된 것을 확인 있다.

 

 

-- 테스트 시나리오 2

-- 아래는 SP_CREATE_PLAN_GUIDE_FROM_HANDLE 으로 플랜을 고정시키는 방법이다.

-- 플랜에 올라온 실행계획을 고정시키는 방법이다.

-- 그러나, 방법으로 MEMORY GRANT 고정시킬 없고, 역시 PARAMETERIZATION FORCE 개별로 ENABLE 시키던지

-- 데이터베이스 전역으로 ENABLE 시켜야 한다.

-- 그러므로 OPTIMIZER FOR 이용해 실행시 PARAMETER 인식시켜 충분한 메모리를 할당 받을

-- 있도록 하는것이 최선의 방법이다.

-- 어떤 방법이든, 방법의 한계를 이해하는 것이 중요하다.

 

-- 역시 SIMPLE 상태에서 파라미터화 해서 쓰기위해서 다음 플랜가이드를 먼저 만든다.

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

EXEC sp_create_plan_guide

    N'PLAN_GUIDE_TEST2',

    @stmt,

    N'TEMPLATE',

    NULL,

    @params,

    N'OPTION(PARAMETERIZATION FORCED)';

GO

 

DBCC FREEPROCCACHE

GO

 

-- 병렬쿼리로 동작 할꺼다.

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 10000000

GO

 

-- 플랜을 받아서 고정시켜보자

-- 그런데 이번에는 스마트하게 SP_CREATE_PLAN_GUIDE_FROM_HANDLE 에서 받아볼까?

 

DECLARE @PLAN_HANDLE VARBINARY(1000)

SELECT @PLAN_HANDLE = PLAN_HANDLE

--SELECT *

  FROM SYS.DM_EXEC_QUERY_STATS QS

 CROSS APPLY SYS.DM_EXEC_SQL_TEXT(QS.SQL_HANDLE) SQT

 WHERE TEXT LIKE '%SUM%SHOPID%PRODUCTID%'

   AND TEXT NOT LIKE '%SYS.DM_EXEC%'

 

SELECT @PLAN_HANDLE

EXEC SP_CREATE_PLAN_GUIDE_FROM_HANDLE 'PLAN_GUIDE_TEST3', @PLAN_HANDLE=@PLAN_HANDLE

GO

 

 

DBCC FREEPROCCACHE

GO

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

GO

 

--MemoryGrant="25736"

 

DBCC FREEPROCCACHE

GO

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 10000000

GO

--MemoryGrant="205960"

 

-- 위와 같이 플랜은 같게 플랜 가이드를 쓰지만 메모리 GRANT 크게 차이가 나고 처음에 0 넣고

-- 돌린 쿼리가 돌게되면 두번째 쿼리 변수가 크면 이번에는 HASH WARNING 발생하면서 TEMPDB SPILL 발생한다.

-- 동작 속도도 엄청나게 떨어지게 된다.

-- 테스트를 완료 했으면, 플랜 가이드를 지운다.

 

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST1')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST1

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST2')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST2

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST3')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST3

GO

 

-- 2 테스트

-- 강제 파라미터화를 위해 PLAN_GUIDE_TEST2 지우지 않았다.

 

 

-- 테이블 힌트를 통해서 플랜가이드를 주었을때 해당 인덱스가 삭제되면

-- 어떻게 될까? (동작하지 않는다.)

-- CREATE NONCLUSTERED INDEX NC_TBLX_02 ON TBLX (PRODUCTID)

GO

 

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

EXEC sp_create_plan_guide

    N'PLAN_GUIDE_TEST2',

    @stmt,

    N'TEMPLATE',

    NULL,

    @params,

    N'OPTION(PARAMETERIZATION FORCED)';

GO

 

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

-- 확인을 위한 쿼리

SELECT @STMT, @PARAMS

 

EXEC SP_CREATE_PLAN_GUIDE

@NAME = N'PLAN_GUIDE_TEST1',

@STMT = @STMT,

@TYPE = N'SQL',

@MODULE_OR_BATCH = NULL,

@PARAMS = @PARAMS,

@HINTS = N'OPTION (TABLE HINT (B, INDEX(NC_TBLX_02)))'

-- QUERY A END

 

 

-- 인덱스 힌트를 주고 해당 인덱스를 삭제할 경우

-- 플랜 가이드에 명시적으로 TABLE HINT 인덱스가 명시되어 있는데 없어지면 실행이 되지 않는다.

 

DROP INDEX TBLX.NC_TBLX_02

GO

 

DBCC FREEPROCCACHE

GO

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

GO

-- 동작하지 않는다.

 

SELECT *

  FROM SYS.PLAN_GUIDES A

 CROSS APPLY SYS.FN_VALIDATE_PLAN_GUIDE (A.PLAN_GUIDE_ID)

GO

 

-- 인덱스 만들면 동작한다.

CREATE NONCLUSTERED INDEX NC_TBLX_02 ON TBLX (PRODUCTID)

GO

 

-- Index 'NC_TBLX_02' on table 'TBLX' (specified in the FROM clause) does not exist.

-- 라고 기록되며 실행되지 않는다.

-- 동일한 인덱스 이름을 만들어 주면 동작한다.

-- 오류가 생기는 시점은 인덱스가 삭제되면 바로 발생한다.

-- 해당 테스트는   JOIN TBLX B WITH(INDEX(NC_TBLX_02)) 힌트를 주더라도 같다.

-- USE PLAN 에서 사용된 인덱스가 없어져도 무시하고 실행되는 경우는

-- 명시적 인덱스 힌트를 사용하지 않고 만들어진 쿼리플랜을 USE PLAN 으로 사용할

-- 인덱스를 지우면 FN_VALIDATE_PLAN_GUIDE 오류가 남고 실행은 된다.

-- 실행은 되나 플랜의 하단 이터레이터에서 속성을 확인하면, 플랜 가이드를 쓰지 않은것을 있다.

 

-- 다른 테스트를 위해 플랜 가이드 제거

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST1

GO

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST2

GO

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST3

GO

 

DBCC FREEPROCCACHE

GO

 

--DROP INDEX TBLX.NC_TBLX_02

--GO

 

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

EXEC sp_create_plan_guide

    N'PLAN_GUIDE_TEST2',

    @stmt,

    N'TEMPLATE',

    NULL,

    @params,

    N'OPTION(PARAMETERIZATION FORCED)';

GO

 

CREATE NONCLUSTERED INDEX NC_TBLX_02 ON TBLX (PRODUCTID)

GO

 

-- 아래 쿼리는 TBLX NC_TBLX_02 쓰는 실행계획이다.

-- 플랜 확인

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

GO

 

-- USE PLAN 이용해 PLAN GUIDE 생성하기

-- QUERY B START

DECLARE @SQL_XML_PLAN NVARCHAR(MAX)

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

 

SELECT @SQL_XML_PLAN =     

       CONVERT(NVARCHAR(MAX),SQP.QUERY_PLAN)

  FROM SYS.DM_EXEC_QUERY_STATS QS

 CROSS APPLY SYS.DM_EXEC_SQL_TEXT(QS.SQL_HANDLE) SQT

 CROSS APPLY SYS.DM_EXEC_QUERY_PLAN(QS.PLAN_HANDLE) SQP

 WHERE TEXT LIKE '%SUM%SHOPID%PRODUCTID%'

   AND TEXT NOT LIKE '%SYS.DM_EXEC%'

 

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 1000000

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

-- 확인을 위한 쿼리

SELECT @STMT, @PARAMS

 

SELECT @SQL_XML_PLAN

   SET @SQL_XML_PLAN = 'OPTION(USE PLAN '''+@SQL_XML_PLAN+''')'

 

EXEC SP_CREATE_PLAN_GUIDE @NAME =N'PLAN_GUIDE_TEST3'

   , @STMT = @STMT

   , @TYPE = N'SQL'

   , @MODULE_OR_BATCH = NULL

   , @PARAMS = @PARAMS

   , @HINTS = @SQL_XML_PLAN

-- QUERY B END

 

DROP INDEX TBLX.NC_TBLX_02

GO

 

-- 플랜 가이드를 무시하고, 클러스터 인덱스를 이용해 실행한다.

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

 

-- 인덱스 삭제등의 문제가 있으면 아래 쿼리로 확인 가능하다.

SELECT *

  FROM SYS.PLAN_GUIDES A

 CROSS APPLY SYS.FN_VALIDATE_PLAN_GUIDE (A.PLAN_GUIDE_ID)

GO

 

-- 인덱스 만들어주면 다시 동작한다.

CREATE NONCLUSTERED INDEX NC_TBLX_02 ON TBLX (PRODUCTID)

GO

 

-- 이번에는 플랜가이드를 사용할 것이다.

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

 

--Index 'DB_PLAN_GUIDE_TEST.dbo.TBLX.NC_TBLX_02', specified in the USE PLAN hint, does not exist. Specify an existing index, or create an index with the specified name.

 

-- 플랜가이드 제거

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST1')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST1

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST2')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST2

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST3')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST3

GO

 

-- 원본 쿼리의 힌트제거 방법

-- 아래와 같이 ISV 개발자가 임으로 HASH JOIN 기술해 개발해 놓았으나

-- 데이터베이스에서는 해당 힌트가 동작하지 않았으면 한다.  (무시하길 원한다.)

-- , 아래 방법은 FROM 절에 JOIN 힌트로 기술되어 있거나, 다른 JOIN 방법을 명시하는 것은 불가능 하다.

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

OPTION (HASH JOIN)

 

-- 1. SIMPLE PARAMETERIZATION 데이터베이스에서 테스트 하기 위해 개별 쿼리에

-- PARAMETERIZATION 활성화 한다.

 

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

OPTION (HASH JOIN)

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

EXEC sp_create_plan_guide

    N'PLAN_GUIDE_TEST2',

    @stmt,

    N'TEMPLATE',

    NULL,

    @params,

    N'OPTION(PARAMETERIZATION FORCED)';

GO

 

-- 2. HINT 절에 NULL 기술해 힌트를 제거한다.

DECLARE @STMT NVARCHAR(MAX);

DECLARE @PARAMS NVARCHAR(MAX);

EXEC SP_GET_QUERY_TEMPLATE N'

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

OPTION (HASH JOIN)

 ',

    @STMT OUTPUT,

    @PARAMS OUTPUT;

 

-- 확인을 위한 쿼리

SELECT @STMT, @PARAMS

 

EXEC SP_CREATE_PLAN_GUIDE

@NAME = N'PLAN_GUIDE_TEST1',

@STMT = @STMT,

@TYPE = N'SQL',

@MODULE_OR_BATCH = NULL,

@PARAMS = @PARAMS,

@HINTS = NULL

-- QUERY A END

GO

 

DBCC FREEPROCCACHE

GO

 

SELECT SUM(A.SHOPID)

  FROM TBLX A

  JOIN TBLX B

    ON A.IDX = B.IDX

 WHERE B.PRODUCTID < 0

OPTION (HASH JOIN)

 

 

-- 플랜가이드 제거

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST1')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST1

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST2')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST2

GO

IF EXISTS (SELECT * FROM SYS.plan_guides WHERE NAME ='PLAN_GUIDE_TEST3')

EXEC SP_CONTROL_PLAN_GUIDE N'DROP', PLAN_GUIDE_TEST3

GO

 

 

 

 

 

http://msdn.microsoft.com/en-us/library/ms191275(v=sql.100).aspx

http://msdn.microsoft.com/en-us/library/ms190417(v=sql.100).aspx

http://blogs.msdn.com/b/sqlblog/archive/2009/02/19/plan-guides-plan-freezing-in-sql-server-2005-2008.aspx

Posted by 보미아빠
, |

adventureworks

카테고리 없음 / 2012. 12. 2. 00:01
http://msftdbprodsamples.codeplex.com/releases/view/93587

 

Posted by 보미아빠
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함