2012-04-10 5 views
5

멍청한 질문 시간. 오라클 10g.조인에 영향을 미치는 Where 절

where 절이 결합에 영향을 줄 수 있습니까? 물론 이것은 인위적인 예입니다

select * from 
(select product, product_name from products p 
join product_serial ps on product.id = ps.id 
join product_data pd on pd.product_value = to_number(p.product_value)) product_result 
where product_name like '%prototype%'; 

:

나는 형태의 쿼리를 가지고있다. 테이블 구조를 보여줄 필요가 전혀 없습니다. 상상을 초월합니다. 불행히도 실제 테이블 구조 나 쿼리를 표시 할 수는 없습니다. 이 경우, p.product_value는 VARCHAR2 필드이며, 특정 행에서는 텍스트가 아닌 내부에 ID가 저장됩니다. (예, 디자인이 좋지 않지만 상속 된 것으로 변경할 수 없습니다.)

문제는 가입에 있습니다. where 절을 생략하면 쿼리가 작동하고 행이 반환됩니다. 그러나 where 절을 추가하면 pd.product_value = to_number (p.product_value) 조인 조건에서 "invalid number"오류가 발생합니다.

분명히 p.product_value 필드에 숫자가 아닌 행이 결합되면 "잘못된 번호"오류가 발생합니다. 그러나, 내 질문에 어떻게 선택되는 행입니까? 외부 where 절없이 조인이 성공하면 outer where 절이 조인 결과에서 행을 선택하면 안됩니까? 어떤 일이 일어나고있는 것은 내부 쿼리에 조인이 있더라도 where 절이 조인 된 행에 영향을주는 것입니다.

제 질문은 의미가 있습니까?

+0

'to_char (pd.product_value) = p.product_value'라는 약간의 여유를 줄 수 있습니다. – briantyler

답변

1

짧은 대답 : 예.

긴 대답 : 동일한 결과를 반환하는 한 쿼리 엔진은 원하는대로 쿼리를 다시 작성할 수 있습니다. 가장 효율적인 쿼리를 생성하기 위해 모든 쿼리를 사용할 수 있습니다.

이 경우에는 원하는 항목을 다루는 인덱스가있는 것 같지만 제품 이름은 where 절에 추가 할 때 인덱스가 사용되지 않고 대신 사용됩니다. 두 조건이 동시에 테스트되므로 오류가 발생합니다.

실제로 조인 조건에서 오류가 발생합니다. 번호가 확실하지 않으면 to_number를 사용하면 안됩니다.

0

귀하의 to_number(p.product_value)은 유효한 product_name 행에만 적용됩니다.

where 절 앞에 join이 적용되어 to_number 함수가 실패하면 어떻게됩니까?

select * from 
(select product, product_name from products p 
join product_serial ps on product.id = ps.id 
join product_data pd on product_name like '%prototype%' AND 
    pd.product_value = to_number(p.product_value)); 
+0

이것은 도움이 될 수도 있고 도움이되지 않을 수도 있습니다 - 오라클이'to_number '를 먼저 평가하는 것을 막을 수있는 방법은 없습니다. –

2

그것은 생성 된 것 계획에 영향을 : 당신이해야 할 일은

이처럼 product_name like '%prototype%'JOIN A와 절을 포함합니다.

테이블을 조인 (및 필터링)하는 실제 순서는 쿼리를 작성한 순서가 아니라 테이블의 통계에 따라 결정됩니다.

한 버전에서 공동으로 생성 된 계획은 '나쁜'행이 절대로 처리되지 않는다는 것을 의미합니다. 선행 조인은 결과 세트를 결코 결합되지 않은 지점으로 필터링했기 때문입니다.

WHERE 절이 도입됨에 따라 ORACLE에서는 이제는 제품 이름별로 필터링하면 특정 인덱스가 필요하거나 많은 데이터가 줄어들 기 때문에 다른 순서로 조인하는 것이 더 좋습니다.

이 새로운 순서는 '나쁜'행을 필터링하기 위해 결합 전에 처리된다는 의미입니다.


나는 그것을 쿼리하기 전에 데이터를 정리하기 위해 노력할 것입니다. 값이 이미 숫자로 형변환 된 파생 열을 만들거나 가능하지 않은 경우 NULL로 남겨 두는 것이 좋습니다.

EXPLAIN PLAN을 사용하여 다른 계획을 쿼리에서 확인할 수도 있습니다.

0

Jonathan Gennick의 Subquery Madness을 읽어 보시기 바랍니다.

기본적으로 문제는 오라클이 모든 순서로 프리디 케이트를 자유롭게 평가할 수 있다는 것입니다. 따라서 product_name 술어를 하위 쿼리에 푸시 (또는 푸시하지 않음) 할 수 있습니다. 어떤 순서로든 조인 조건을 평가할 수 있습니다. 따라서 오라클이 to_number을 적용하기 전에 숫자가 아닌 product_value 행을 걸러내는 쿼리 계획을 선택하면 쿼리가 성공합니다. 숫자가 아닌 product_value 행을 필터링하기 전에 to_number을 적용한 계획을 선택하면 오류가 발생합니다. 물론, 첫 번째 N 개의 행을 성공적으로 반환 할 수도 있습니다. N + 1 행이 to_number 술어를 처음으로 적용하려고하기 때문에 N + 1 행을 페치하려고하면 오류가 발생합니다. 비 숫자 데이터로 변환합니다.

데이터 모델을 수정하는 것 이외에 쿼리에 일부 힌트를 던져서 오라클이 to_number 조건자를 적용하기 전에 모든 비 숫자 데이터가 필터링되도록하는 조건부를 강제로 평가하도록 할 수 있습니다. 그러나 일반적으로 옵티마이 저가 항상 "적절한"순서로 항목을 평가하도록하는 방식으로 쿼리를 완전히 힌트를 표시하는 것은 다소 어려운 일입니다.