"비용"이 시간의 측면에 있다고 가정하면 (;-의 측면에서 다른 것이 무엇인지 확실하지는 않지만) 최소한 다음과 같은 작업을 수행하여이를 이해할 수 있어야합니다.
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
SET STATISTICS TIME ON;
EXEC sp_help 'sys.databases'; -- replace with your proc
SET STATISTICS TIME OFF;
"메시지"탭에보고 된 첫 번째 항목은 다음과 같아야합니다.
SQL Server 구문 분석 및 컴파일 시간 :
이 작업을 최소 10 회 실행하고 평균 "CPU"및 "경과 된"밀리 초를 사용합니다.
이상적으로는 실제 시간을 예상 할 수 있도록 프로덕션 환경에서이를 실행하지만 프로덕션 환경에서 계획 캐시를 지울 수있는 사람은 거의 없습니다. 다행히 SQL Server 2008부터는 캐시에서 특정 계획을 지울 수있게되었습니다. 어떤 경우에는 다음을 수행 할 수 있습니다.
DECLARE @SQL NVARCHAR(MAX) = '';
;WITH cte AS
(
SELECT DISTINCT stat.plan_handle
FROM sys.dm_exec_query_stats stat
CROSS APPLY sys.dm_exec_text_query_plan(stat.plan_handle, 0, -1) qplan
WHERE qplan.query_plan LIKE N'%sp[_]help%' -- replace "sp[_]help" with proc name
)
SELECT @SQL += N'DBCC FREEPROCCACHE ('
+ CONVERT(NVARCHAR(130), cte.plan_handle, 1)
+ N');'
+ NCHAR(13) + NCHAR(10)
FROM cte;
PRINT @SQL;
EXEC (@SQL);
SET STATISTICS TIME ON;
EXEC sp_help 'sys.databases' -- replace with your proc
SET STATISTICS TIME OFF;
그러나, 값의 변화에 따라가 "나쁜"캐시 된 계획을 유발하는 매개 변수 (들)에 대한 전달되고, 그 사이의 중간 고려해야하는 또 다른 방법이있다 OPTION(RECOMPILE)
및 OPTION(OPTIMIZE FOR UNKNOWN)
동적 SQL :. 그렇습니다. 그리고 매개 변수가없는 Dynamic SQL도 의미합니다. 이유는 다음과 같습니다.
최소한 하나 이상의 입력 매개 변수 값과 관련하여 분포가 고르지 않은 데이터가 분명히 있습니다. 언급 된 옵션의 단점은 다음과 같습니다.
OPTION(RECOMPILE)
모든 실행을위한 계획을 생성하고 당신이 혜택을 누릴 수 없을 것입니다 어느 다시 전달 된 매개 변수 값은 이전에 실행 (들)과 동일한 경우에도, 계획 재사용. 자주 (몇 초에 한 번 또는 더 자주) 호출되는 프로의 경우 가끔 끔찍한 상황에서 벗어날 수 있지만 항상 그다지 좋은 상황은 아닙니다.
OPTION(OPTIMIZE FOR (@Param = value))
특정 값을 기반으로 계획을 생성하여 여러 경우에 도움이 될 수 있지만 여전히 현재 문제에 대해 개방적입니다.
OPTION(OPTIMIZE FOR UNKNOWN)
평균 분포에 해당하는 금액을 기준으로 계획을 생성하여 일부 쿼리에 도움이되지만 다른 쿼리에는 피해를줍니다. 로컬 변수를 사용하는 옵션과 동일해야합니다.
그러나 동적 SQL 은 올바르게 수행되면 전달되는 다양한 값에 이상적인 별도의 쿼리 계획을 갖도록 허용합니다 (잘 될 것입니다). 여기서 주요 비용은 전달되는 다양한 값이 증가함에 따라 캐시의 실행 계획 수가 증가하고 메모리를 차지한다는 것입니다. 사소한 비용은 다음과 같습니다.
그래서 여기 초당 1 회 이상 호출 된 프로세서가 있고 각각 수백만 개의 행이있는 여러 테이블에 부딪쳤을 때이 상황을 관리 한 방법이 있습니다. 나는 시도 OPTION(RECOMPILE)
했지만 매개 변수 스니핑 / 잘못된 캐시 계획 문제가없는 99 %의 경우 프로세스에 너무 해로운 것으로 판명되었습니다. 이러한 proc 중 하나에는 약 15 개의 쿼리가 있으며 여기에 설명 된대로 3-5 개만 Dynamic SQL로 변환되었습니다. 특정 쿼리에 필요하지 않으면 동적 SQL이 사용되지 않았습니다.
스토어드 프로 시저에 여러 입력 매개 변수가있는 경우, 데이터 분산이 매우 높은 열에 사용되는 매개 변수 (이로 인해이 문제점이 발생 함)와 더 고른 분포가있는 열에 사용되는 매개 변수를 파악하십시오. 이 문제의 원인).
균일하게 분산 된 열과 연관된 proc 입력 매개 변수의 매개 변수를 사용하여 동적 SQL 문자열을 빌드하십시오. 이 매개 변수화는이 쿼리와 관련된 캐시에서 실행 계획의 결과 증가를 줄이는 데 도움이됩니다.
매우 다양한 분포와 관련된 나머지 매개 변수의 경우이 값을 리터럴 값으로 Dynamic SQL에 연결해야합니다. 고유 쿼리는 쿼리 텍스트에 대한 변경 사항에 따라 결정되므로을 갖는 WHERE StatusID = 1
것과 다른 쿼리를 가지므로 쿼리 계획이 다릅니다 WHERE StatusID = 2
.
쿼리 텍스트에 연결될 proc 입력 매개 변수 중 하나가 문자열 인 경우, SQL 주입을 방지하기 위해 유효성을 검증해야합니다 (전달되는 문자열이 다음에 의해 생성되는 경우 발생할 가능성은 적음) 앱이 아닌 사용자). 적어도 REPLACE(@Param, '''', '''''')
작은 따옴표가 이스케이프 된 작은 따옴표가되도록하십시오.
필요한 경우, 사용자를 작성하는 데 사용될 인증서를 작성하고 스토어드 프로 시저에 서명하여 직접 테이블 권한이 새 인증서 기반 사용자에게만 부여되고 [public]
그렇지 않으면 해당 권한이없는 사용자에게 부여되지 않도록합니다. .
proc 예 :
CREATE PROCEDURE MySchema.MyProc
(
@Param1 INT,
@Param2 DATETIME,
@Param3 NVARCHAR(50)
)
AS
SET NOCOUNT ON;
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'
SELECT tab.Field1, tab.Field2, ...
FROM MySchema.SomeTable tab
WHERE tab.Field3 = @P1
AND tab.Field8 >= CONVERT(DATETIME, ''' +
CONVERT(NVARCHAR(50), @Param2, 121) +
N''')
AND tab.Field2 LIKE N''' +
REPLACE(@Param3, N'''', N'''''') +
N'%'';';
EXEC sp_executesql
@SQL,
N'@P1 INT',
@P1 = @Param1;