SQL 문을 sargable로 만드는 것은 무엇입니까?


252

sargable은 정의에 의해 (적어도 내가 본 것에서) 쿼리 엔진이 쿼리가 사용하는 실행 계획을 최적화하도록 할 수 있음을 의미합니다. 나는 답을 찾으려고 노력했지만 주제에 대해서는별로없는 것 같습니다. 따라서 질문은 SQL 쿼리를 Sargable로 만들거나 만들지 않는 것입니다. 모든 문서는 대단히 감사하겠습니다.

참고 : SARGable


58
"sargable"에 +1 그것이 오늘 오늘의 나의 말입니다. :-p
BFree 2018

1
또한 정보의 산은 대부분의 경우 각 DB 엔진에 매우 특별하다는 Adam의 대답에 덧붙일 수 있습니다.
Hoagie

30
SARG = 검색 ARGument. 재미있는 점은 : 독일어로 "SARG"는 "관"을 의미하므로 사람들이 SARGABLE에 대해 이야기 할 때 항상 웃어야합니다. 관에 넣을 수 있습니까? :-)
marc_s

Sargability는 환경에 따라 다릅니다. MySQL은 여기에 문서화되어 있습니다 : dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer

"조회 테이블"대신 자유 텍스트 필드를 갖는 것은 쿼리를 다루기 쉽게 만드는 정신에 위배됩니다. 사용자는 자유 텍스트 (예 : 도시 이름)를 입력 할 때 맞춤법이 틀린 반면 조회 테이블을 사용하면 철자가 올바른 항목을 선택해야합니다. 술어에서 LIKE '% ... %'를 사용하는 대신 올바르게 색인화 할 수 있기 때문에 약간의 추가 문제점이 있습니다.
리버스 엔지니어

답변:


256

쿼리를 처리 불가능 하게 만드는 가장 일반적인 것은 where 절의 함수 내에 필드를 포함시키는 것입니다 .

SELECT ... FROM ...
WHERE Year(myDate) = 2008

SQL 옵티마이 저는 myDate에 인덱스가 존재하더라도이를 사용할 수 없습니다. 문자 그대로 테이블의 모든 행에 대해이 함수를 평가해야합니다. 사용하는 것이 훨씬 낫습니다.

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

다른 예 :

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 

7
내부에 함수를 포함 GROUP BY시키면 쿼리를 처리 할 수 ​​없게됩니까?
Mike Bailey

1
일부 데이터베이스 엔진 (Oracle, PostgreSQL)은 표현식에서 인덱스를 지원합니다.
Craig

3
더 나은 버전 WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL될까요? 예를 들어 where 절에서 OR을 사용하면 쿼리를 취소 할 수 없다는 최적화 담당자가 한 번 들었습니다.
High Plains Grifter

2
@HighPlainsGrifter 당신은 그 쿼리에 UNION ALL을 사용해야합니다-유니언은 암시 적 구별을 가지고 있기 때문에 상호 배타적 인 데이터 세트가 필요할 때보 다 쿼리가 훨씬 비쌉니다.
Devin Lamothe

1
@BradC MSSQL에서 2016 사이의 어떤 실시 계획 차이가 없다 Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'하고 Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). 둘 다 FullName의 인덱스를 사용하고 인덱스 검색을 수행합니다.
CEGRD

79

이 작업을 수행하지 마십시오 :

WHERE Field LIKE '%blah%'

LIKE 값은 와일드 카드 문자로 시작하기 때문에 테이블 / 인덱스 스캔이 발생합니다.

이 작업을 수행하지 마십시오 :

WHERE FUNCTION(Field) = 'BLAH'

테이블 / 인덱스 스캔이 발생합니다.

데이터베이스 서버는 테이블의 모든 행에 대해 FUNCTION ()을 평가 한 후 'BLAH'와 비교해야합니다.

가능하면 반대로 수행하십시오.

WHERE Field = INVERSE_FUNCTION('BLAH')

이 매개 변수에 대해 INVERSE_FUNCTION ()을 한 번 실행하고 인덱스 사용을 계속 허용합니다.


5
함수를 뒤집는 제안은 함수가 데이터를 왕복 할 때만 작동합니다 (f (f (n)) = n을 의미).
Adam Robinson

5
진실. INVERSE_FUNCTION 추가를 고려했지만 혼동하고 싶지 않았습니다. 변경하겠습니다.
beach

9

이 답변에서는 데이터베이스에 충분한 커버링 인덱스가 있다고 가정합니다. 이 주제 에 대해 충분한 질문 있습니다.

쿼리의 sargability는 많은 경우 관련 인덱스의 티핑 포인트에 의해 결정됩니다. 티핑 포인트는 한 테이블이나 결과 집합을 다른 테이블이나 조인하는 동안 인덱스 검색과 검색의 차이를 정의합니다. 한 번의 탐색은 전체 테이블을 스캔하는 것보다 훨씬 빠르지 만 많은 행을 탐색해야 할 경우 스캔이 더 의미가 있습니다.

따라서 옵티마이 저가 한 테이블의 결과 행 수가 다음 테이블에서 가능한 인덱스의 팁 포인트보다 적을 것으로 예상 할 때 SQL 문을보다 잘 이해할 수 있습니다.

자세한 게시물과 예제는 여기에서 찾을 수 있습니다 .


4

작업을 sargable로 간주하려면 기존 인덱스를 사용하는 것만으로는 충분하지 않습니다. 위의 예에서 where 절의 색인화 된 열에 대해 함수 호출을 추가하면 정의 된 색인을 활용할 가능성이 높습니다. 해당 열 (인덱스)에서 모든 값을 "스캔"한 다음 제공된 필터 값과 일치하지 않는 값을 제거합니다. 행 수가 많은 테이블에는 여전히 효율적이지 않습니다. sargability를 실제로 정의하는 것은 정렬 된 항목 배열에 대한 반 집합 제거에 의존하는 이진 검색 방법을 사용하여 b-tree 인덱스를 순회하는 쿼리 기능입니다. SQL에서는 실행 계획에 "인덱스 찾기"로 표시됩니다.

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