where 절 또는 백만 + 행 테이블과의 조인이 더 효율적인 것은 무엇입니까?


17

한 테이블에 250MM 개의 행이있는 웹 사이트를 실행하고 대부분의 쿼리에 대해 다른 테이블에 연결하는 웹 사이트는 15MM 미만입니다.

샘플 구조 :

MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows

우리는 정기적으로 이러한 모든 테이블에 대해 몇 가지 쿼리를 수행해야합니다. 하나는 무료 사용자 (~ 10k 무료 사용자)에 대한 통계를 얻는 것입니다.

Select Count(1) from DetailsTable dt 
join MasterTable mt on mt.Id = dt.MasterId 
join UserTable ut on ut.Id = mt.UserId 
where ut.Role is null and mt.created between @date1 and @date2

문제는이 쿼리가 조인이 어디보다 오래 전에 발생한다는 사실 때문에 오랜 시간이 걸리는 것입니다.

이 경우 조인 또는 가능한 위치를 사용하는 것이 더 현명 where column in(...)합니까?


1
어떤 데이터베이스와 버전?
레이 리펠

1
두 가지 방법을 모두 사용해 보셨습니까?
gbn

이것이 Oracle이라면 NVL2 (Role, NULL, ID)에서 UserTable에 대한 함수 기반 인덱스를 만들지 만 다른 DB처럼 보입니다.
레이 리펠

답변:


20

최신 RDBMS의 경우 성능 및 쿼리 계획과 관련하여 "명시 적 JOIN"과 "JOIN-in-the-WHERE"(모든 JOINS가 INNER 인 경우)간에 차이가 없습니다.

명시 적 JOIN 구문은 명확하고 모호하지 않습니다 (아래 링크 참조).

이제 어디서나 합류하는 것은 실제 처리가 아닌 논리 처리이며 현대 옵티마이 저는이를 실현할만큼 영리합니다.

여기서 문제는 색인 생성 가능성이 높습니다.

이 테이블의 모든 색인과 키를 보여주십시오. 그리고 쿼리 계획

참고 :이 질문은 지금까지 복제 된 것에 대해 StackOverflow에서 닫 혔을 것입니다 ... COUNT (1) vs COUNT (*)는 또 다른 혼란스러운 신화입니다.


2
joinwhere절 사이에 차이가 없다고 항상 참인 것은 아닙니다 . 나는 오랫동안 실행되는 쿼리를 항상 최적화하며 때로는 쿼리 사용 where절이 join최대 70 배의 요소를 사용 하는 쿼리 보다 성능이 우수 합니다. 그것이 간단하고 간단하다면 인생은 모든 무지개와 유니콘이 될 것입니다. 그리고 이것은 고대의 애매 모호한 엔진에 관한 것이 아닙니다. 지금 당장 where은 SQL 2012 에서 70 배의 절 이점을보고 있습니다 .
ajeh

더욱이 필자는 종종 두 접근 방식에서 정확히 동일한 계획을 관찰하고 쿼리가 정확히 동일한 성능을 수행하지만 where절 쿼리가 큰 배치 내에서 실행될 때 그 일부가 될 것으로 예상되면 join쿼리 보다 성능이 크게 향상됩니다. SQL 쿼리는 진공 상태에서 실행되지 않습니다. 이들은 나머지 서버 페이로드의 영향을받으며 종종 where쿼리 쿼리가 상당히 잘 이루어 지므로 join구문이 실제로 더 깔끔해 지기 때문에 성 가실 수 있습니다.
ajeh

3
@ajeh : 귀하의 경험이 매우 비정형 적이라고 제안합니다. x70 차이가있는 경우 쿼리에 더 큰 문제가 있습니다. 간단합니다
gbn

5

쿼리를 모두 리 팩터해야합니다

앞서 WHERE 절을 수행하고 나중에 JOIN을 수행하십시오.

Select Count(1) from DetailsTable dt
join (Select UserId,Id FROM MasterTable where
created between @date1 and @date2) mt on mt.Id = dt.MasterId 
join (Select Id FROM UserTable WHERE Role is NULL) ut
on ut.Id = mt.UserId;

이 리팩토링 된 쿼리에 대해 EXPLAIN 계획을 실행하고 원래보다 나빠 보이는 경우에도 시도하십시오. 내부적으로 작성된 임시 테이블은 데카르트 조인을 수행하지만 해당 테이블은 작업하기에 더 작습니다.

이 YouTube 비디오에서이 아이디어를 얻었습니다 .

나는 StackOverflow에서 매우 복잡한 질문으로 비디오의 원리를 시험해 보았고 200 포인트 현상금을 얻었습니다.

@gbn은 올바른 인덱스가 있는지 확인했습니다. 이 경우 MasterTable에서 생성 된 열을 인덱싱하십시오.

시도 해봐 !!!

업데이트 2011-06-24 22:31 EDT

다음 쿼리를 실행해야합니다.

SELECT COUNT(1) AllRoles FROM UserTable;
SELECT COUNT(1) NullRoles FROM UserTable WHERE Role is NULL;

NullRoles X 20 <AllRoles 인 경우 (즉, NullRoles가 테이블 행의 5 % 미만인 경우) UserTable에서 고유하지 않은 인덱스 역할을 작성해야합니다. 그렇지 않으면 Query Optimizer가 색인을 사용하여 제외 할 수 있으므로 UserTable의 전체 테이블로 충분합니다.

업데이트 2011-06-25 12:40 EDT

나는 MySQL DBA이기 때문에 일을하는 방법에는 긍정적 비관론을 통해 MySQL Query Optimizer를 신뢰할 필요가 없으며 보수적이어야합니다. 따라서 MySQL Query Optimizer의 숨겨진 나쁜 습관을 극복하기 위해 쿼리를 리팩토링하거나 필요한 커버링 인덱스를 작성해 보겠습니다. @gbn의 대답은 SQL Server가 쿼리를 평가하는 "마음의 정도"가 더 높을 수 있다는 점에서 더 완벽 해 보입니다.


0

약 75M 행의 [Detail] 테이블이있었습니다. 400K 개의 행에 대한 [Master] 테이블과 항상 7 개의 행을 가진 관련 [Item] 테이블. 소량의“품목 번호”(1-7)를 저장하고 매월 수백만 장을 인쇄하여 배포하는 종이 양식을 모델링했습니다. 가장 빠른 쿼리는 카티 전 조인 (Cartesian Join) 사용과 관련하여 가장 적게 생각한 것입니다. IIRC는 다음과 같습니다.

SELECT m.order_id, i.line_nr, d.Item_amt
FROM Master m, Item i 
INNER JOIN Detail d ON m.order_id = d.order_id

[Item]과 [Detail] 사이에 논리적 "id"링크가 있지만 CROSS JOIN은 INNER JOIN보다 효과적이었습니다.

RDBMS는 MPP 기술이 적용된 Teradata였으며 IDR은 인덱싱 체계였습니다. TABLE SCAN이 항상 최상의 성능을 발휘했기 때문에 7 개의 행 테이블에는 인덱스가 없습니다.

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