sql 쿼리 Join시 카테시안 곱 주의(with sqlAlchemy)
보통 JOIN 시에 조건을 주지 않았을 때 발생한다고 한다.
상식적으로 생각해봐도 JOIN 조건이 없다면 기준이 되는 테이블(Outer Table)과 대상 테이블(Inner Table) 간에 관계가 만들어지지 않는다.
postgresql 쿼리에서 JOIN
문이 ON
조건없이 조인을 할 수 없으며, 위 내용의 조건이란 다음과 같은 쿼리를 의미한다.
- 조건없는 조인
SECLECT * FROM Table1, Table2;
- 조건있는 조인
SELECT * FROM Table1, Table2 WHERE TABLE1.id = TABLE2.id;
위 예의 조건없는 조인과 같이 관계(WHERE
)가 만들어지지 않은 채로 JOIN을 하게 되면 Error가 발생하지 않고 양 테이블의 row간에 대카테시안 곱의 방식의 결합이 일어난다. 기준 테이블 row의 개수 100, 대상 테이블 row 개수 200 이라면 카테시안 곱의 결과 20000개의 row를 가진 테이블이 결과로 반환된다. 만약 1000 * 1000 이라면 1000000 (백만) 개의 결과가 발생한다.
개발 초기에 데이터의 양이 적을 때는 이런 오류를 발견하지 못할 수도 있다. 그래서 더욱 주의해야한다.SQLAlchemy로 쿼리를 만들 때
query_select = session.query( Tbale1, Table2, Table3)
query_join = query_select.join(Table1, condision1 ) # 카테시안 곱 존재
query_join = query_join.join(Table2, condisions2 ) # 카테시안 곱 존재
query_join = query_join.join(Table3, condision3 ) # 카테시안 곱 없음
query_result = query_join.one()
위 코드에서 처음 query_select
에서 명시된 테이블은 Table1
, Table2
, Table3
의 3개다.
이 세개의 테이블은 쿼리 결과에 선택되는 테이블이며 JOIN
을 하기 전까지 테이블간에 어떤 관계도 없다. 따라서 결과는 카테시안 곱 이 된다.
이런 결과를 의도적일 수도 있지만 일반적인 경우는 의도적이지 않다.
이들 간에 관계는 WHERE
또는 JOIN
문을 사용하여 만들 수 있다.
query_select에서 선택된 테이블에 대해서는 반드시 JOIN
을 하도록 하자.
또는 query_select
에서 테이블 간 관계를 정의하는 filter
를 넣을 수도 있겠다.
query_select = session.query( Tbale1, Table2, Table3).filter( conditions )
마지막으로 explain
을 사용하여 직접 실행될 쿼리의 계획을 확인하도록 해보자.