#title Hash Match/Cache [[TableOfContents]] ==== 환경 ==== 다음과 같은 환경에 놓여져 있다. {{{ use tempdb go select * into test_details from Northwind..[Order Details] Go create index idx_test on test_details(ProductID, UnitPrice) Go select * into test from Northwind..Products Go create index idx_test on test(ProductID) go --결과 ProductID Max_UnitPrice ----------- --------------------- 1 18.0000 2 19.0000 3 10.0000 4 22.0000 5 21.3500 6 25.0000 7 30.0000 8 40.0000 9 97.0000 10 31.0000 }}} 일반적으로 대부분의 사람들은 위와 같은 환경에서 아래와 같은 SQL의 형태로 주로 작성한다. 하지만 이것은 80%점이다. Index를 최대한 이용할 수 있는 형태라면 Hash Match/Cache 연산을 이용하면 조인의 횟수를 줄일 수 있다. {{{ --쿼리2 select a.ProductID , Max(b.UnitPrice) Max_UnitPrice from test a inner join test_details b on a.ProductID = b.ProductID where a.ProductID <= 10 group by a.ProductID Go --'test_details' 테이블. 스캔 수 10, 논리적 읽기 수 20, 물리적 읽기 수 0, 미리 읽기 수 0. --'test' 테이블. 스캔 수 1, 논리적 읽기 수 1, 물리적 읽기 수 0, 미리 읽기 수 0. }}} attachment:hash_match_cache01.jpg ==== Hash Match/Cache ==== {{{ --쿼리1 select a.ProductID , (select top 1 UnitPrice from test_details b where a.ProductID = b.ProductID order by UnitPrice desc) from test a where ProductID <= 10 Go --'test_details' 테이블. 스캔 수 10, 논리적 읽기 수 20, 물리적 읽기 수 0, 미리 읽기 수 0. --'test' 테이블. 스캔 수 1, 논리적 읽기 수 1, 물리적 읽기 수 0, 미리 읽기 수 0. }}} attachment:hash_match_cache02.jpg ==== 두 쿼리의 실행계획 비교 ==== attachment:hash_match_cache03.jpg 단순히 논리적 읽기 수만 비교했을 때는 같지만, 연산의 횟수는 눈에 띄게 줄었다. 대략 20배이상. 루프를 2,000번 도는 것과 200,000번 도는 것은 분명히 성능차이가 발생한다. ==== SQL Server 2005 이후 버전에서는.. ==== 참고로 2005 버전 이후부터는 Hash Match/Cache 키워드가 없어졌다. 하지만 SET STATISTICS PROFILE ON 으로 실행계획을 보면 SQL Server 2000처럼 2005, 2008이 동작한다는 것을 알 수 있다. 단지 Hash Match/Cache를 볼 수 없을 뿐이다. 내부적인 연산으로 감춘 것 같은데 이 자랑하기 좋은 것을 왜 감췄는지는 알 수 없다. 어쨌든 Hash Match/Cache의 효과를 보기 위해서는 Index Design도 중요하다. Hash Match/Cache는 Covered Index를 사용하는 쿼리에서만 동작한다.