2011-05-05 7 views
3

많은 작업에 동적 SQL을 사용하고 동일한 문제로 계속 실행됩니다. 동적 T-SQL 문에서 사용되는 변수 값 인쇄.동적 매개 변수 값 인쇄

EG : 위의 코드의

Declare @SQL nvarchar(max), @Params nvarchar(max), @DebugMode bit, @Foobar int 
select @DebugMode=1,@Foobar=364556423 

set @SQL='Select @Foobar' 
set @Params=N'@Foobar int' 

if @DebugMode=1 print @SQL 
exec sp_executeSQL @SQL,@Params 
    ,@[email protected] 

인쇄 결과는 단순히 "선택 @Foobar"입니다. 거기에 동적으로 값을 & 실행중인 SQL의 변수 이름을 인쇄하는 방법이 있습니까? 또는 인쇄를 수행 할 때 SQL을 다시 실행할 수 있도록 매개 변수를 실제 값으로 바꿉니 까?

데이터 형식 변환, 패턴 매칭 잘라 내기 문제 및 비 동적 솔루션을 사용하여 비슷한 기능을 구현하는 데 하나 또는 두 가지 기능을 함께 사용했습니다. 다른 개발자가 수동으로 각 변수를 수동으로 인쇄하지 않고 어떻게이 문제를 해결하는지 궁금합니다. 대부분의 사람들이 그것을 할 방법의 주제에

+0

에서 성능 튜닝, 문제 해결, 감사, 다른 목적으로 더 자주 할이 뭔가를 분할 기능을 사용? –

+0

@ Phil Helmer, 일반적으로 문제 해결에 사용되지만 때로는 좀 더 복잡한 동적 쿼리의 성능 튜닝을 수행 할 때 사용됩니다. –

답변

3

나는 당신이 문 '으로 캐시를 명중 볼 것이다 어디서든 지속되지 않습니다'를 선택 @FooBar이 '로 심지어 프로파일 러 추적에

을'364,556,243 선택 '당신의 예제 쿼리를 의미하는 평가 문을 사용할 생각하지 말아 (@Foobar int) select @foobar '

sp_executesql을 사용할 때 큰 이점은 변수가 평가되지 않은 신뢰할 수있는 형식으로 명령문을 캐시 할 수 있다는 것입니다. 그렇지 않으면 변수를 대체하고 우리는 실행 계획이 부풀어 오르는 것을 볼 것입니다.

업데이트 : 입력 (@Statement, @ParamDef, @ParamVal)와,이 모든 정리하고 좋은 기능에 싸여 수

및 반환 :가 여기에 올바른 방향으로에 걸음 "준비된"진술. 나는 그 중 일부를 당신을위한 운동으로 남겨 둘 것이지만, 그것을 향상시킬 때 다시 게시하십시오!

이다, 그냥 사용 시나리오의 더 나은 사진을 얻기 위해 여기 link

set nocount on; 

declare @Statement varchar(100), -- the raw sql statement 
     @ParamDef varchar(100), -- the raw param definition 
     @ParamVal xml    -- the ParamName -to- ParamValue mapping as xml 


-- the internal params: 
declare @YakId int, 
     @Date datetime 
select @YakId = 99, 
     @Date = getdate(); 


select @Statement = 'Select * from dbo.Yak where YakId = @YakId and CreatedOn > @Date;', 
     @ParamDef = '@YakId int, @Date datetime'; 

-- you need to construct this xml manually... maybe use a table var to clean this up 
set @ParamVal = ( select * 
        from ( select '@YakId', cast(@YakId as varchar(max)) union all 
           select '@Date', cast(@Date as varchar(max)) 
          ) d (Name, Val) 
        for xml path('Parameter'), root('root') 
       ) 

-- do the work 
declare @pStage table (pName varchar(100), pType varchar(25), pVal varchar(100)); 
;with 
    c_p (p) 
    as ( select replace(ltrim(rtrim(s)), ' ', '.') 
      from dbo.Split(',', @ParamDef)d 
     ), 
    c_s (pName, pType) 
    as ( select parsename(p, 2), parsename(p, 1) 
      from c_p 
     ), 
    c_v (pName, pVal) 
    as ( select p.n.value('Name[1]', 'varchar(100)'), 
        p.n.value('Val[1]', 'varchar(100)') 
      from @ParamVal.nodes('root/Parameter')p(n) 
     ) 
insert into @pStage 
    select s.pName, s.pType, case when s.pType = 'datetime' then quotename(v.pVal, '''') else v.pVal end -- expand this case to deal with other types 
    from c_s s 
    join c_v v on 
      s.pName = v.pName 

-- replace pName with pValue in statement 
select @Statement = replace(@Statement, pName, isnull(pVal, 'null'))      
from @pStage 
where charindex(pName, @Statement) > 0; 

print @Statement; 
+0

아무 곳에 나 유지되지 않고 있다고 생각했지만 누군가를 원했습니다. 적절한 데이터 유형을 유지하면서 값을 동적으로 대체하는 마법의 해결책을 가졌습니다. –

+0

좋아, 나는이 '마법의'하지만 그 시작 전화 wouldnt : –

+0

나는 그것을 좋아한다. 이 답변을 위해 작성 했습니까? 아니면 이미 반복적으로 사용하고있는 것입니까? 또한 "다른 사람들이 어떻게합니까?"라는 질문에 대해 @Brent D의 질문에 대해 다른 사람들로부터 답변을 듣는 것이 훨씬 더 궁금합니다. 공유해 주셔서 감사합니다. –

2

, 난 단지 내가 무엇을 말하는 것입니다 :

  • 이 유효하고 유효하지 않은 입력의 넓은 범위를 사용하여 프로 시저를 실행하는 테스트 스크립트를 작성합니다. 매개 변수가 정수이면 4 대신 4를 보내 겠지만 'agd'와 같은 1 개의 홀수 문자열 값만 시도합니다.
  • 내가하는 일에 대한 대표 크기 및 데이터 값 분포의 데이터 집합에 대해 값을 실행합니다. 이 속도를 높이려면 좋아하는 데이터 생성 도구 (시중에는 여러 가지 좋은 도구가 있습니다)를 사용하십시오.
  • 저는 일반적으로 SSMS 결과 창에서 결과를 수집하는 것이 제가 취해야 할만큼 멀리있는 상황에서 좀 더 특별하게 디버깅하고 있습니다.

내가 생각할 수있는 가장 좋은 방법은 SQL Trace를 사용하여 전선을 가로 질러 오는 쿼리를 캡처하는 것입니다. 쿼리 문자열에 (주석으로) 고유 한 항목을 배치하면 추적에 필터를 적용하여 필요한 것보다 많이 캡처하지 못하게 할 수 있습니다.

그러나 복숭아는 모두 & 크림이 아닙니다.

이것은 개발자 환경에 따라 QA 인 경우에만 적합합니다.

쿼리를 실행하는 데 시간이 오래 걸리는 경우 @DebugMode = 1 인 경우 쿼리 문자열에 "TOP 1", "WHERE 1 = 2"또는 유사한 제한 조항을 추가하여 완화 할 수 있습니다. 매번 끝내기 위해 잠시 기다릴 수 있습니다.

디버그 모드에 대해서만 쿼리 문자열을 추가 할 수없는 긴 쿼리의 경우 StmtStarted 이벤트에서 명령 텍스트를 캡처 한 다음 명령을받는 즉시 쿼리를 취소 할 수 있습니다.

쿼리가 INSERT/UPDATE/DELETE 인 경우 @DebugMode = 1이고 변경을 원하지 않으면 강제로 롤백해야합니다. 현재 명시 적 트랜잭션을 사용하고 있지 않은 경우 추가 오버 헤드가 발생합니다.

이 길로 가면 삶을 편하게하기 위해 얻을 수있는 자동화가 있습니다. 트레이스 생성 및 시작/정지 작업을위한 템플릿을 생성 할 수 있습니다. 결과를 파일이나 테이블에 기록하고 프로그래밍 방식으로 명령 텍스트를 처리 할 수 ​​있습니다.

+0

이것은 @ DevMode = 1 인 경우에만 Dev 또는 QA에만 있거나 프로덕션의 롤백 트랜잭션에서 수동으로 쿼리를 실행하는 경우에만 적용됩니다. 나는 SQL Trace가 매개 변수가 값으로 대체되지 않는 원시 쿼리 만 표시 할 것이라고 생각합니다. 예 : "select @Foobar"및 "select"Foobar의 텍스트 " –