TVP가 READONLY 여야하는 이유와 다른 유형의 매개 변수를 READONLY 할 수없는 이유


19

이 블로그 에 따르면 함수 또는 저장 프로 시저에 대한 OUTPUT매개 변수 는 매개 변수 가 아닌 경우 기본적으로 값으로 전달되며 매개 변수 인 경우 기본적으로 안전한 참조 별 전달로 취급됩니다 OUTPUT.

처음에 TVP를 강제로 선언하는 목표는 READONLY개발자에게 TVP를 OUTPUT매개 변수 로 사용할 수 없다는 것을 명확하게 알리는 것이지만 TVP가 아닌 것을로 선언 할 수 없기 때문에 계속 진행해야 할 것이라고 생각했습니다 READONLY. 예를 들어 다음은 실패합니다.

create procedure [dbo].[test]
@a int readonly
as
    select @a

메시지 346, 수준 15, 상태 1, 프로 시저 테스트
매개 변수 "@a"는 테이블 반환 매개 변수가 아니므로 읽기 전용으로 선언 할 수 없습니다.

  1. 통계가 TVP에 저장되지 않기 때문에 DML 작업을 방지하는 데 필요한 근거는 무엇입니까?
  2. OUTPUT어떤 이유로 TVP를 매개 변수 로 사용하지 않으려는 것과 관련이 있습니까?

답변:


19

설명은 a)이 질문에서 언급되지 않은 링크 된 블로그의 세부 사항, b) 매개 변수가 항상 전달 및 전달되는 방식에 적합한 TVP의 실용성, c) 및 본질의 조합과 관련이있는 것으로 보입니다. 테이블 변수

  1. 링크 된 블로그 게시물에 누락 된 세부 사항은 변수가 저장 프로 시저 및 함수로 전달되는 방법과 정확히 일치합니다 ( "OUTPUT 매개 변수 인 경우보다 안전한 참조에 의한 전달 버전"의 질문에 대한 문구) :

    TSQL은 copy-in / copy-out 시맨틱을 사용하여 저장 프로 시저 및 함수에 매개 변수를 전달합니다.

    ... 저장된 프로 시저가 (오류없이) 실행을 마치면 복사 된 프로 시저에서 변경된 내용으로 전달 된 매개 변수를 업데이트하는 복사가 수행됩니다.

    이 접근법의 실제 이점은 오류 사례입니다. 저장 프로 시저 실행 도중 오류가 발생하면 매개 변수에 대한 변경 내용이 호출자에게 다시 전파되지 않습니다.

    OUTPUT 키워드가 없으면 복사가 수행되지 않습니다.

    결론 :
    저장된 proc에 대한 매개 변수는 오류가 발생한 경우 저장된 proc의 부분 실행을 반영하지 않습니다.

    이 퍼즐의 1 부에서는 매개 변수가 항상 "값으로"전달 된다는 것 입니다. 그리고,이 같은 매개 변수가 표시되어있는 경우에만입니다 OUTPUT 저장 프로 시저가 현재 값이 실제로 다시 전송되는 것을 성공적으로 완료됩니다. OUTPUT값이 실제로 "참조로"전달 된 경우 해당 변수의 메모리 위치에 대한 포인터는 값 자체가 아니라 전달 된 것입니다. 포인터 (예 : 메모리 주소)를 전달하면 저장 프로 시저의 다음 줄에서 오류가 발생하여 실행이 중단 되더라도 변경 사항이 즉시 반영됩니다.

    1 부 요약 : 변수 값은 항상 복사됩니다. 그것들은 그들의 메모리 주소에 의해 참조되지 않습니다.

  2. Part 1을 염두에두고, 변수 값을 항상 복사하는 정책은 전달되는 변수가 상당히 클 때 자원 문제를 야기 할 수 있습니다. 내가 BLOB 유형을 처리하는 방법을보고 테스트하지 않았습니다 ( VARCHAR(MAX), NVARCHAR(MAX), VARBINARY(MAX), XML, 더 이상 사용할 수 없습니다 것들 : TEXT, NTEXT,과 IMAGE),하지만 데이터의 테이블이 매우 큰 수에 전달되는 것을 말하는 것이 안전합니다. TVP 기능을 개발하는 사람들은 멋진 새로운 기능이 건강한 수의 시스템을 파괴하지 못하도록 (즉, 더 확장 가능한 접근 방식을 원하는) 진정한 "기준 별 통과"기능을 원하는 것이 합리적입니다. 당신 이 문서 에서 볼 수 있듯이 그들이 한 일 :

    Transact-SQL은 입력 데이터의 복사본을 만들지 않도록 참조로 테이블 반환 매개 변수를 루틴에 전달합니다.

    또한이 메모리 관리 문제는 SQL Server 2005에 도입 된 SQLCLR API (TVP는 SQL Server 2008에 도입 됨)에서 찾을 수 있으므로 새로운 개념이 아닙니다. 통과 할 때 NVARCHARVARBINARY(A SQLCLR 어셈블리 내에서 .NET 방법에 즉, 입력 매개 변수)를 SQLCLR 코드로 데이터, 당신이 중 하나를 사용하여 "값에 의해"접근로 이동 할 수있는 옵션이 SqlString또는 SqlBinary각각을하거나 "참조로 갈 수 있습니다 " SqlChars또는 SqlBytes각각 을 사용하여 접근하십시오 . SqlCharsSqlBytes유형은 (최대 2GB 오른쪽) 전체 200메가바이트를 복사에 값을 반대로 큰 값의 작은 덩어리를 당길 수 있도록 .NET CLR로 데이터의 전체 스트리밍 할 수 있습니다.

    2 부 요약 : TVP는 본질적으로 "항상 가치를 모방"모델 내에 머무르면 많은 메모리를 소비하고 (따라서 성능 저하) 경향이 있습니다. 따라서 TVP는 진정한 "통과 기준"을 수행합니다.

  3. 마지막 부분은 Part 2가 중요한 이유입니다. 왜 TVP를 전달하는 것이 무엇이든 변경하지 않고 진정으로 "참조로"전달하는 것입니다. 그리고 성공적으로 완료되지 않은 Part 1 : Stored Procedures의 기초가되는 설계 목표에 의해 응답됩니다. 입력 매개 변수가 표시되어 있는지 여부에 관계없이 입력 매개 변수를 변경해서는 OUTPUT안됩니다. DML 작업을 허용하면 호출 컨텍스트에있는 TVP의 값에 즉각적인 영향을 미칩니다 (참조로 전달하면 전달 된 내용의 복사본이 아니라 전달 된 내용을 변경한다는 의미이므로).

    이제 누군가가이 시점에서 모니터와 대화하고있을 것입니다. "저장 프로 시저로 전달 된 TVP 매개 변수에 대한 변경 사항을 롤백하기 위해 자동 기능을 구축하십시오. Duh. 문제가 해결되었습니다." 그렇게 빠르지 않습니다. 이것이 바로 테이블 변수의 특성입니다. 테이블 변수에 대한 변경 사항은 트랜잭션에 의해 구속되지 않습니다! 따라서 변경 사항을 롤백 할 방법이 없습니다. 실제로 롤백이 필요한 경우 트랜잭션 내에서 생성 된 정보를 저장하는 데 사용되는 트릭입니다.

    3 부 요약 : 테이블 변수는 저장 프로 시저가 중단되도록하는 오류가 발생한 경우 "실행 취소"변경을 허용하지 않습니다. 그리고 이것은 부분 실행 (파트 1)을 반영하지 않는 매개 변수를 갖는 설계 목표를 위반합니다.

고로 :READONLY 키워드는 실제로 "참조로"전달되는 테이블 변수이기 때문에 TVPs에 DML 작업을 방지하기 위해 필요하지 않습니다, 따라서 그들에 대한 수정 사항은 즉시 반영 할 것, 저장 프로 시저에 오류가 발생하더라도 더있다 이를 방지하는 다른 방법입니다.

또한 다른 데이터 형식의 매개 변수 READONLY는 이미 전달 된 내용의 복사본이므로 사용할 수 없으므로 아직 보호되지 않은 항목은 보호하지 않습니다. 그리고 다른 데이터 유형의 매개 변수가 작동하는 방식은 읽기 / 쓰기를위한 것이기 때문에 이제 읽기 전용 개념을 포함하도록 해당 API를 변경하는 것이 훨씬 더 많은 작업 일 것입니다.


매우 자세한 설명. 감사. 따라서 저장 프로 시저 로 전달 된 테이블 변수 (사용자 TVP TYPE변수 또는 a DECLARE x as TABLE (...)) 를 수정할 수있는 방법이 없습니까? set @tvp = myfunction(@tvp)함수의 RETURNS값이 TVP 유형과 동일한 DDL을 가진 테이블 인 경우 대신 함수를 사용하여 메모리 풋 프린트가 더 크더라도이를 수행 할 수 있습니까 ?
mpag

@mpag 감사합니다. TVP 테이블 변수이며 차이는 없습니다. 유형을 전달하지 않고 유형 또는 명시 적 스키마 선언에서 작성된 테이블 변수를 전달합니다. 또한 SET적어도 내가 알고있는 테이블 변수 는 사용할 수 없습니다 . =a) 운영자 를 통해 결과 집합에 액세스 할 수없고 b) TVP가 여전히으로 표시되어 READONLY있으므로 설정을 위반하면 위반 될 수 있습니다. 내용을 임시 테이블 또는 proc 내에서 작성한 다른 테이블 변수에 덤프하십시오.
Solomon Rutzky

다시 감사합니다. 본질적으로 임시 테이블 접근 방식을 사용하기로 결정했습니다.
mpag

5

Martin Smith 의 질문에 대한 코멘트에서 생성 된 커뮤니티 위키 답변

이를 위해 활성화 된 Connect 항목 (Erland Sommarskog에서 제출)이 있습니다.

SP가 서로를 호출 할 때 테이블 매개 변수가 읽기 전용이어야한다는 제한 완화

지금까지 Microsoft의 유일한 답변은 다음과 같습니다 (강조 추가).

이에 대한 의견을 보내 주셔서 감사합니다. 많은 고객으로부터 유사한 피드백을 받았습니다. 테이블 값 매개 변수를 읽거나 쓸 수있게하려면 클라이언트 프로토콜뿐만 아니라 SQL 엔진 쪽에서도 많은 작업이 필요합니다. 시간 / 자원 제약과 기타 우선 순위로 인해 SQL Server 2008 릴리스의 일부로이 작업을 수행 할 수 없습니다. 그러나이 문제를 조사하고 다음 SQL Server 릴리스의 일부로 해결하기 위해이 문제를 레이더에 확실하게 적용했습니다. 의견을 보내 주셔서 감사합니다.

Srini Acharya
선임 프로그램 관리자
SQL Server Relational Engine

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.