SQL Server 에서 매개 변수 화 된 SQL 쓰기 가 parameter sniff 를 만 나 계획 을 불합리 하 게 실행 하고 재 활용 하 는 빠 른 해결 방법 을 만 났 습 니 다.
이러한 상황 은 실제 업무 에서 나타 나 는 빈도 가 비교적 높다.저장 과정 은 일반적으로 매개 변수 화 된 표기 법 을 사용 하기 때문이다.이때 분포 가 고 르 지 않 은 데이터 파 라 메 터 를 만 났 을 때 파 라 메 터 sniff 현상 이 나타 나 는데 이런 문 제 는 비교적 골 치 아프다.
구체 적 인 parameter sniff 가 발생 한 원인 에 대해 저 는 너무 많은 설명 을 하지 않 겠 습 니 다.이것 을 설명 하면 너무 낮 아 보 입 니 다.
저 는 간단 한 예 를 들 어 이 현상 을 모 의 한 다음 에 매개 변수 화 된 저장 과정 을 어떻게 썼 는 지,어떤 문제 가 존재 하 는 지,그리고 parameter sniff 문 제 를 어떻게 해결 하 는 지 설명 하 겠 습 니 다.
테스트 환경 만 들 기:
create table ParameterSniffProblem
(
id int identity(1,1),
CustomerId int,
OrderId int,
OrederStatus int,
CreateDate Datetime,
Remark varchar(200)
)
declare @i int = 0
while @i<500000
begin
INSERT INTO ParameterSniffProblem values (@i%10000,@i,RAND()*10,GETDATE()-RAND()*100,NEWID())
set @i=@i+1
end
-- ,
INSERT INTO ParameterSniffProblem values (6666,RAND()*100000,1,GETDATE()-RAND()*100,NEWID())
GO 100000
--
CREATE CLUSTERED INDEX IDX_CreateDate on ParameterSniffProblem(CreateDate
)
CREATE INDEX IDX_CustomerId ON ParameterSniffProblem(CustomerId)
매개 변수 화 저장 프로 세 스 의 쓰기:저장 프로 세 스 를 작성 할 때 저 희 는 일반적으로 매개 변수 화 된 쓰기 방법 을 사용 하 는 것 을 권장 합 니 다.저장 프로 세 스 의 컴 파일 을 줄 이 고 실행 계획 캐 시 를 강화 하기 위해 서 입 니 다.
대략 이렇다
CREATE PROCEDURE [dbo].ParameterSniffTest
(
@p_CustomerId int,
@p_Status int,
@p_FromDate datetime,
@p_ToDate datetime
)
AS
BEGIN
SET NOCOUNT ON
DECLARE
@Parm NVARCHAR(MAX),
@sqlcommand NVARCHAR(MAX) = N''
SET @sqlcommand = 'SELECT * FROM ParameterSniffProblem WHERE 1=1'
IF(@p_CustomerId IS NOT NULL)
SET @sqlcommand = CONCAT(@sqlcommand,'AND CustomerId=@p_CustomerId ')
IF(@p_Status IS NOT NULL)
SET @sqlcommand = CONCAT(@sqlcommand,'AND OrederStatus=@p_Status ')
IF(@p_FromDate IS NOT NULL)
SET @sqlcommand = CONCAT(@sqlcommand,'AND CreateDate>=@p_FromDate ')
IF(@p_ToDate IS NOT NULL)
SET @sqlcommand = CONCAT(@sqlcommand,'AND CreateDate<=@p_ToDate ')
SET @Parm= '@p_CustomerId int,
@p_Status int,
@p_FromDate datetime,
@p_ToDate datetime '
EXEC sp_executesql @sqlcommand,@Parm,
@p_CustomerId = @p_CustomerId,
@p_Status = @p_Status,
@p_FromDate = @p_FromDate,
@p_ToDate = @p_ToDate
END
GO
파라미터 Sniff 문제:이것 은 파 라 메 터 sniff 문제 가 잠재 되 어 있 습 니 다.
예 를 들 어 저 는 사용자 ID=100 의 주문 정 보 를 조회 하고 정상 적 인 분포 데 이 터 를 조회 합 니 다.저장 과정 이 처음으로 컴 파일 되 었 는데 이 실행 계획 은 전혀 문제 가 없습니다.
만약 에 제 가 파 라 메 터 를 바 꾸 어 사용자 6666 의 정 보 를 조회 하고 분포 와 불 균형 한 데 이 터 를 실행 합 니 다.그러나 상기 캐 시 실행 계획 을 다시 사용 하기 때문에 파 라 메 터 sniff 문제 가 발생 합 니 다.이 실행 계획 은 분명 합 리 적 이지 않 습 니 다.
IO 는 보지 않 고 일부러 만 든 예 입 니 다.
만약 에 제 가 실행 계획 캐 시 를 비우 고 상기 조 회 를 다시 실행 합 니 다.재 컴 파일 이 있 기 때문에 실행 계획 은 이 렇 지 않 습 니 다.CustomerID=6666 이라는 매개 변수 에 있어 서 전체 표 스 캔 대 가 는 더욱 작 아야 합 니 다.
이것 은 개발 에서 흔히 볼 수 있 는 문제 일 것 입 니 다.우리 에 게 매개 변수 화 SQL 은 서로 다른 매개 변수 에 대한 조 회 를 재 활용 하여 계획 을 실행 하 게 하 는 것 입 니 다.그러나 불행 하 게 도 데이터 분포 가 고 르 지 않 을 때 재 활용 계획 은 데이터 베이스 에 데 미 지 를 입 혔 습 니 다.예 를 들 어 정상 적 인 매개 변수 가 분포 가 많은 데 이 터 를 재 활용 한 실행 계획 이 라면 이름 은 색인 을 사용 할 수 있 습 니 다.결 과 는 시계 스 캔 이 고 결 과 는 더욱 심각 할 것 이다.
그렇다면 가능 한 한 실행 계획 을 재 활용 하고 싶 을 뿐만 아니 라 실행 계획 재 활용 으로 인해 parameter sniff 문제 가 발생 하지 않도록 하려 면 어떻게 해 야 합 니까?
우 리 는@p 가 문제 라 는 것 을 안다.customerId 에 게 parameter sniff 문제 가 발생 할 수 있 는@pcustomerId 는 매개 변수 화 를 하지 않 고 SQL 에 직접 맞 춥 니 다.만약@pcustomerId 가 변 하면 SQL 을 다시 컴 파일 합 니 다.즉,들 어 오 는@p 입 니 다.CustomerId 재 컴 파일
@p 라면customerId 는 변 하지 않 습 니 다.다른 매개 변 수 는 변화 가 있 습 니 다.예 를 들 어 이 시간 필드 의 변 화 는 매개 변수 화가 가 져 온 실행 계획 재 활용 의 장점 도 누 릴 수 있 습 니 다.즉,이렇게 처리 하 는 것 입 니 다@pcustomerId 이 매개 변 수 는@pcustomerId 가 SQL 문장 에 문자열 로 평평 하 게 모 으 면 즉석에서 조회 하 는 것 과 같 습 니 다.매개 변수 화 된 방식 으로 customerId 라 는 조회 조건 필드 에 값 을 부여 하지 않 습 니 다.
IF(@p_CustomerId IS NOT NULL)
SET @sqlcommand = CONCAT(@sqlcommand,'AND CustomerId= ',@p_CustomerId)
이렇게 저장 과정 을 수행 할 때,@p 가 져 오기CustomerId=1 시,IDX 실행customerId 의 index seek
@p 가 져 오기customerId=6666 시 재 컴 파일,실행 계획 은 전체 표 스 캔 으로 위 에서 생 성 된 실행 계획 을 재 활용 하지 않 고 불합리한 실행 방식 이 효율 과 데이터 베이스 서버 자원 에 대한 소 모 를 초래 합 니 다.
이렇게 하면 parameter sniff 문제 가 가 져 오 는 영향 을 최대한 줄 일 수 있 습 니 다.캐 시 되 어 있 을 때@pcustomerId=1 의 실행 계획 을 실행 할 때 다시@pcustomerId=1,다른 조건 은 비교적 작은 변화 가 있 습 니 다.예 를 들 어 시간 필드 에 변경 이 있 으 면 캐 시 실행 계획 을 다시 사용 하여 컴 파일 에 미 치 는 영향 을 피 할 수 있 습 니 다.
결론:
이런 방식 은 parameter sniff 문 제 를 처리 하 는 것 입 니 다.물론 완벽 한 것 은 아 닙 니 다.분명 문제 가 있 을 것 입 니 다.저 는 당연히@pCustomerId 가 다 르 면 다시 컴 파일 해 야 합 니 다.
틀림없이@pcustomerId 매개 변수 값 이 다 르 기 때문에 재 컴 파일 의 기 회 를 피 할 수 없습니다.
그러나 불합리한 실행 계획 재 활용 으로 인 한 parameter sniff 문 제 는 없 을 것 이다.
parameter sniff 문제 가 발생 하면 대량의 조회 가 불합리한 실행 계획 을 사용 하면 전체 서버 에 심각 한 영향 을 미 칠 수 있다 는 것 을 알 아야 한다.예 를 들 어 대량의 IO 등 이 발생 할 수 있다.
첫 번 째@pCustomerId=1,
다시@pcustomerId=1.다른 조건 은 작은 변화 가 있 습 니 다.예 를 들 어 시간 필드 에 변경 이 있 으 면 캐 시 실행 계획 을 다시 사용 할 수 있 습 니 다.재 컴 파일 이 가 져 온 영향 을 피 할 수 있 습 니 다.물론 저 는 간단 한 예 일 뿐 실제 응용 에서 이것 보다 훨씬 복잡 합 니 다.
예 를 들 어 분 포 된 유 난 히 많은 데 이 터 는 두 가지 특징 이 있다.첫 번 째 분포 의 표 시 는 하나만 있 는 것 이 아니 라 두 번 째 분포 가 고 르 지 않 은 데 이 터 는 동태 적 인 것 이다.첫 번 째 분 포 는 A 라 는 부분의 데이터 가 대부분 을 차지 할 수도 있 고 두 번 째 분 포 는 B 데이터 가 절대 다 수 를 차지 할 수도 있다.
그래서 Plan Guide 로 parameter sniff 문 제 를 해결 하기 가 쉽 지 않 습 니 다.
이 방식 은 캐 시 실행 계획 을 어느 정도 재 활용 할 수 있 고 재 컴 파일 횟수 를 줄 일 수 있 습 니 다.
이 동시에 이런 방식 은 SQL 문자열 을 조합 하여 실행 하 는 즉석 조회 방식 에 비해 매개 변수 화가 가 져 온 다른 장점 도 이용 할 수 있다.예 를 들 어 SQL 주입 등 이다.
요약:
parameter sniff 문제 해결 방식 이 많 습 니 다.일일이 말 하지 않 겠 습 니 다.
가장 전형 적 인 것 은 강제 재 컴 파일 이다.
혹은 EXEC 를 사용 하여 맞 춤 형 문자열 을 실행 합 니 다.이 방식 은 adhoc 조회 에 속 합 니 다.
힌트 를 조회 하거나,
로 컬 변 수 를 사용 하거나,
플랜 가이드 등 을 사용 하거나,
모든 방식 은 그의 한계 가 있다.적어도 지금까지 파 라 메 터 sniff 문 제 를 해결 하 는 완벽 한 방법 은 없다.
문제 에 부 딪 히 면 해결 방법 은 여러 가지 가 있 는데,최소한 의 대가 로 문 제 를 해결 하 는 것 이 왕도 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
우분투에 SQL 서버 설치Microsoft SQL Server는 오늘날 업계에서 가장 눈에 띄는 데이터베이스 중 하나입니다. 이번 포스팅에서는 우분투에 설치하는 방법을 알려드리겠습니다. sudo 권한이 있는 계정 1단계: 터미널 열기 단축키...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.