SQL 쿼리와 같은 여러 열을 최적화하기위한 모범 사례는 무엇입니까?
-
19-08-2019 - |
문제
상속 받고 최적화하려는 검색 쿼리가 있습니다. 누구나 모범 사례와 권장 사항이 있는지 궁금합니다. 프로덕션 서버는 여전히 SQL Server 2000입니다.
쿼리는 5 백만 레코드 테이블을 검색하기 위해 5 개의 다른 검색 기준 매개 변수 (예 : 이름, 성, 주소, 전화 등)를 수용하는 고급 고객 검색 저장 프로 시저입니다. WHERE 절에 결합 된 모든 열 및 열에 인덱스가 있습니다. 또한 초기 쿼리는 레코드를 페이징 용량을위한 테이블 변수로 덤프합니다.
INSERT INTO @tempCustTable (CustomerID, FirstName, LastName, City, StateProvince, Zip, PhoneNumber)
SELECT DISTINCT cu.CustomerID, cu.FirstName, cu.LastName, a.City,
a.StateProvince, a.Zip, p.PhoneNumber
FROM Customer cu WITH(NOLOCK)
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID
WHERE (cu.LastName = @LastName OR cu.LastName LIKE @LastName + '%')
AND (@FirstName IS NULL OR cu.FirstName = @FirstName OR cu.FirstName LIKE @FirstName + '%')
AND (@StateProvince = '' OR a.StateProvince LIKE @StateProvince)
AND (@City = '' OR a.City LIKE @City + '%')
AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%')
ORDER BY cu.LastName, cu.FirstName
쿼리의 성능을 향상시킬 수있는 방법에 대한 권장 사항이 있습니까?
해결책
이 전체 라인이 아닙니다
AND (@Zip = '' OR a.Zip = @Zip OR a.Zip LIKE @Zip + '%')
이와 동일합니다
AND (a.Zip LIKE @Zip + '%')
확실히
AND (a.Zip LIKE @Zip + '%')
그것은 동일합니다
a.Zip = @Zip OR a.Zip LIKE @Zip + '%'
다른 팁
SQLMenace가 시작으로 지적한 것처럼 코드에서 많은 중복성을 확실히 정리할 수 있습니다.
또 다른 것은 삽입 된 ..Select와 함께 사용해서는 안된다는 것입니다. 이 맥락에서 주문은 의미가 없습니다. 사람들은 때때로 그것을 사용하여 신원 칼럼이 특정 방식으로 행동하도록 강요하지만, 그것은 나쁜 습관 IMO입니다.
이것이 당신의 상황에서 도움이 될지 모르겠지만, 최근에 나온 한 가지는 저장 프로 시저에서 SQL Server (2005 년을 사용하지만 2000 년에도 사실)가 OR을 단락하지 않을 것이라는 점이었습니다. 많은 경우 상태. 예를 들어, 사용할 때 :
@my_parameter IS NULL OR my_column = @my_parameter
@my_parameter의 널 값을 전달하더라도 후반을 여전히 평가합니다. 저장 절차를 다시 컴파일하도록 설정했을 때도 발생했습니다 (및 SELECT). 속임수는 사례 명세서를 사용하여 단락을 강요하는 것이 었습니다. 그 트릭을 사용하고 (중복성을 제거) 당신의 진술은 다음과 같습니다.
INSERT INTO @tempCustTable
(
CustomerID,
FirstName,
LastName,
City,
StateProvince,
Zip,
PhoneNumber
)
SELECT DISTINCT
cu.CustomerID,
cu.FirstName,
cu.LastName,
a.City,
a.StateProvince,
a.Zip,
p.PhoneNumber
FROM Customer cu WITH(NOLOCK)
LEFT OUTER JOIN Address a WITH(NOLOCK) ON cu.CustomerID = a.CustomerID
LEFT OUTER JOIN Phone p WITH(NOLOCK) ON cu.CustomerID = p.CustomerID
WHERE
(cu.LastName LIKE @LastName + '%') AND
(1 =
CASE
WHEN @FirstName IS NULL THEN 1
WHEN cu.FirstName LIKE @FirstName + '%' THEN 1
ELSE 0
END
) AND
(1 =
CASE
WHEN @StateProvince = '' THEN 1
WHEN a.StateProvince = @StateProvince THEN 1
ELSE 0
END
) AND
(1 = CASE
WHEN @City = '' THEN 1
WHEN a.City LIKE @City + '%' THEN 1
ELSE 0
END
) AND
(1 = CASE
WHEN @Zip = '' THEN 1
WHEN a.Zip LIKE @Zip + '%' THEN 1
ELSE 0
END
)
쿼리를 더 길고 조금 더 복잡하게 만들지 만 더 나은 성능을 위해 가치가있을 수 있습니다. 이것은 특히 당신의 기준에 단락 될 수있는 하위 쿼리가 포함되어있는 경우 true.
드디어... 일관성을 유지하십시오 매개 변수로. @firstName의 경우 NULL 값을 확인하여 사용되었는지 여부를 확인하지만 다른 사람들은 빈 줄을 확인하고 있습니다. 기본 코딩 101 여기에주의를 기울여야합니다.
내 SQL 코드가 '%'를 추가하지 않으려 고 노력하지만 대신 매개 변수에 이미 가지고있을 것으로 기대합니다. 물론 응용 프로그램에서 검증 한 후에는 이렇게합니다! 그런 다음 '='비교를 포함하지 말고 항상 사용하십시오.
여기서 (cu.lastname like @lastname)
대신에:
여기서 (cu.lastname = @lastname 또는 cu.lastname like @lastname + '%')
- 피하는 "또는"S- 일반적으로 인덱스 사용을 방지합니다.
- 왼쪽에 "%"를 넣지 마십시오. - 같은 이유.
동적 SQL로 쿼리를 구축 할 수 있습니다. 그것은 대부분의 OR을 제거하고 사용자가 실제로 입력 한 매개 변수에 대한 WHERE 문선에만 포함해야한다는 것을 의미합니다.
이 작업을 수행하면 EXEC 대신 SP_EXECUTESQL을 사용하여 동적 SQL을 매개 변수화하여 쿼리 계획을 캐시 할 수 있습니다.