SQL Server 2012에서 두 쿼리 비교


14

SQL Server 2012에서 두 쿼리를 비교하고 있습니다. 목표는 최상의 쿼리를 선택할 때 쿼리 최적화 프로그램에서 사용할 수 있는 모든 관련 정보 를 사용하는 것입니다 . 두 쿼리 모두 동일한 결과를 생성합니다. 모든 고객의 최대 주문 ID

FREEPROCCACHE 및 DROPCLEANBUFFERS를 사용하여 각 쿼리를 실행하기 전에 버퍼 풀 지우기가 수행되었습니다.

아래 제공된 정보를 사용하여 어떤 쿼리가 더 나은 선택입니까?

-- Query 1 - return the maximum order id for a customer
SELECT orderid, custid
FROM Sales.Orders AS O1
WHERE orderid = (SELECT MAX(O2.orderid)
                 FROM Sales.Orders AS O2
                 WHERE O2.custid = O1.custid);


-- Query 2 - return the maximum order id for a customer
SELECT MAX(orderid), custid
FROM Sales.Orders AS O1
group by custid
order by custid

통계 시간

쿼리 1 통계 시간 : CPU 시간 = 0ms, 경과 시간 = 24ms

쿼리 2 통계 시간 : CPU 시간 = 0ms, 경과 시간 = 23ms

통계 IO

쿼리 1 통계 IO : 테이블 '주문'. 스캔 횟수 1, 논리적 읽기 5, 물리적 읽기 2, 미리 읽기 0, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0

쿼리 2 통계 IO : 테이블 '주문'. 스캔 카운트 1, 논리적 읽기 4, 물리적 읽기 1, 미리 읽기 8, lob 논리적 읽기 0, lob 물리적 읽기 0, lob 미리 읽기 0.

실행 계획

여기에 이미지 설명을 입력하십시오

SELECT 속성 쿼리 1

여기에 이미지 설명을 입력하십시오

SELECT 속성 쿼리 2

여기에 이미지 설명을 입력하십시오

결론 :

쿼리 1

  1. 배치 비용 48 %
  2. 논리적 읽기 5
  3. 물리적 읽기 2
  4. 미리 읽기 : 0
  5. CPU 시간 : 0ms
  6. 경과 시간 24ms
  7. 예상 하위 트리 비용 : 0.0050276
  8. 컴파일 CPU : 2
  9. 메모리 : 384
  10. 컴파일 시간 : 2

쿼리 2

  1. 배치 비용 52 %
  2. 논리 읽기 4
  3. 물리적 읽기 1
  4. 미리 읽기 : 8
  5. CPU 시간 0
  6. 경과 시간 23ms
  7. 예상 하위 트리 비용 : 0.0054782
  8. 컴파일 CPU : 0
  9. 메모리 : 192
  10. 컴파일 시간 : 0

개인적으로 Query 2는 그래픽 계획에 따라 배치 비용이 높지만 Query 1보다 효율적이라고 생각합니다. 보다 낮은. 미리 읽기는 쿼리 2의 경우 8이고 쿼리 1의 경우 0입니다.

업데이트 12:03

클러스터형 인덱스 정의

ALTER TABLE [Sales].[Orders] ADD  CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED 
(
    [orderid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

비 클러스터형 인덱스 idx_nc_custid

CREATE NONCLUSTERED INDEX [idx_nc_custid] ON [Sales].[Orders]
(
    [custid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
Paul White 9

답변:


10

쿼리 튜닝 및 옵션 및 계획 검토에 대한 신중한 고려에 대한 귀하의 접근 방식을 좋아합니다. 더 많은 개발자들이 이것을하기를 바랍니다. 한 가지주의 할 점은 항상 많은 행으로 테스트하고 논리적 읽기를 살펴보면 작은 테이블입니다. 샘플로드를 생성 한 후 쿼리를 다시 실행하십시오. 하나의 작은 문제-상위 쿼리에서 귀하는 하위 쿼리에서 주문을 요청하지 않습니다. 순서와 비교하고 대조해야합니다.

방금 20 만 건의 판매 주문이 포함 된 SalesOrders 테이블을 신속하게 만들었습니다. 그리고 각각에 ORDER BY를 사용하여 쿼리를 실행했습니다. 나는 또한 인덱스로 조금 연주했다.

OrderID에 클러스터 된 인덱스가 없으면 CustID클러스터되지 않은 인덱스 만 수행됩니다 . 두 번째 쿼리는 성능이 저하되었습니다 . 특히 주문에 따라 포함되어 있습니다. 첫 번째 쿼리에서 두 번째 쿼리보다 두 배 많은 읽기가 있었으며 쿼리 간의 비용 백분율은 67 % / 33 %였습니다.

OrderID의 클러스터 된 인덱스와 CustID의 비 클러스터형 인덱스 를 사용하여 비슷한 속도와 정확히 동일한 수의 읽기를 수행했습니다.

따라서 행 수를 늘리고 더 많은 테스트를 수행하는 것이 좋습니다. 하지만 귀하의 검색어에 대한 최종 분석-

행을 늘릴 때 알고있는 것보다 더 유사하게 동작 할 수 있으므로주의해야 할 점을 염두에두고 테스트하십시오.

반품하려는 모든 고객이 각 고객의 최대 주문 ID이고 주문 ID가 가장 큰 주문 ID임을 확인하려는 경우이 두 가지 중 두 번째 쿼리가 내 사고 방식을 따르는 가장 좋은 방법입니다. 서브 트리 비용을 기준으로 간단하고 비용이 조금 더 비싸지 만 명령문을 빠르고 쉽게 해독 할 수 있습니다. 언젠가 결과 집합에 다른 열을 추가하려는 경우? 그런 다음 첫 번째 쿼리를 통해 그렇게 할 수 있습니다.

업데이트 : 귀하의 질문에 대한 귀하의 의견 중 하나는 다음과 같습니다.

이 질문에서 가장 좋은 쿼리를 찾는 것은 이들을 비교하는 데 사용되는 기술을 개선하는 수단이라는 점을 명심하십시오.

그러나 더 많은 데이터로 테스트를 수행하기위한 최선의 방법은 항상 생산 및 예상되는 미래 생산과 일치하는 데이터를 갖도록하는 것입니다. 쿼리 계획은 테이블에 더 많은 행을 제공 할 때 데이터를 찾기 시작하고 프로덕션에서 예상 한 분포를 유지하려고 시도합니다. 그리고 Order By를 포함하거나 그렇지 않은 것에주의를 기울이십시오. 여기서 나는 그것이 끔찍한 차이를 만들지 않지만 여전히 파고들 가치가 있다고 생각하지 않습니다.

이 수준의 세부 사항과 데이터를 비교하는 방법은 좋습니다. 하위 트리 비용은 대부분 임의적이며 의미가 없지만 최소한 편집 / 변경 또는 쿼리 간 비교를 위해 여전히 가치가 있습니다. 작업중인 데이터의 크기와 수행하려는 작업에 적합하지 않은 항목에 대한 계획을 검토 할 때 시간 통계와 IO를 보는 것이 매우 중요합니다.


다시 한번 더 많은 양의 데이터를 사용하는 것에 대해 감사합니다. 누군가가 처음으로 이것을 제기 한 것은 아닙니다. 마지막으로 페이지 분할에서 가능한 조각화를 고려해야했습니다. 200,000 개의 행 샘플에서 조각화를 확인 했습니까?
Craig Efrein

내 작은 빠른 200k 행 예제에서는 조각화에 중점을 두지 않았습니다. 그러나 내가 한 방식은 없습니다. 테이블을 생성하고 채운 다음 인덱스를 만들었으므로 새로 생성 된 인덱스입니다. 그리고 그것은 주요 질문으로 보이는 쿼리 계획을 보는 접근법을 바꾸지 않을 것입니다. 쿼리 계획을 정확하게 볼 때 데이터의 양이 매우 큽니다. 나는 종종 1-10 행의 dev에서 훌륭하게 보이고 실제 데이터로 끔찍한 경우를 보았습니다. 그러나 귀하의 접근 방식은 훌륭하고 희망적 으로이 정보와 의견의 대화가 도움이됩니다.
Mike Walsh

우리는 custid를 기준으로 그룹화하고 있기 때문에 어떻게 custid 값을 무작위로 만들었습니까? 내가 읽은 내용에서 기억 나는 것은 분명한 가치의 중요성입니다. 상거래가 소수의 개별 고객 만있는 경우 스트림 집계 비용은 비현실적입니다.
Craig Efrein

방금 RAND 기능을 사용하여 100 명의 고객을 작성하고 각 orderID에 하나씩 할당했습니다. 빠른 점검을 수행하고있었습니다. :)
Mike Walsh

모든 도움에 감사드립니다. 마지막 질문입니다. 내 질문에 제공된 2012 년 실행 계획의 SELECT 속성 화면에서 어떤 값에주의를 기울입니까?
Craig Efrein
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.