한 테이블에 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(...)
합니까?
답변
최신 RDBMS의 경우 성능 및 쿼리 계획과 관련하여 “명시 적 JOIN”과 “JOIN-in-the-WHERE”(모든 JOINS가 INNER 인 경우)간에 차이가 없습니다.
명시 적 JOIN 구문은 명확하고 모호하지 않습니다 (아래 링크 참조).
이제 어디서나 합류하는 것은 실제 처리가 아닌 논리 처리이며 현대 옵티마이 저는이를 실현할만큼 영리합니다.
여기서 문제는 색인 생성 가능성이 높습니다.
이 테이블의 모든 색인과 키를 보여주십시오. 그리고 쿼리 계획
참고 :이 질문은 지금까지 복제 된 것에 대해 StackOverflow에서 닫 혔을 것입니다 … COUNT (1) vs COUNT (*)는 또 다른 혼란스러운 신화입니다.
답변
쿼리를 모두 리 팩터해야합니다
앞서 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가 쿼리를 평가하는 “마음의 정도”가 더 높을 수 있다는 점에서 더 완벽 해 보입니다.
답변
약 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 개의 행 테이블에는 인덱스가 없습니다.