oracle : where 절의 함수가 결과를 필터링한 나머지 모든 where 절 이후에만 호출되도록 하는 방법?
저는 이와 같은 취지로 질문을 씁니다.
select *
from players
where player_name like '%K%
and player_rank<10
and check_if_player_is_eligible(player_name) > 1;
이제 check_if_player_is_elitable() 함수가 무겁기 때문에 쿼리가 검색 결과를 충분히 필터링한 다음 필터링된 결과에 대해서만 이 함수를 실행하기를 원합니다.
기능이 실행되기 전에 최소한의 횟수만큼 실행되도록 모든 필터링이 수행되는지 확인하려면 어떻게 해야 합니까?
다른 모든 WHERE 절을 평가하기 전에 Oracle이 함수를 평가하지 않도록 속일 수 있는 두 가지 방법은 다음과 같습니다.
로넘 사용
열
rownum
서브쿼리에서 오라클은 서브쿼리를 "구체화"해야 합니다.예를 들어, 예를 들어 Tom 스레드를 묻습니다.SELECT * FROM (SELECT * FROM players WHERE player_name LIKE '%K%' AND player_rank < 10 AND ROWNUM >= 1) WHERE check_if_player_is_eligible(player_name) > 1
문서 참조 "Nested Subquery의 중첩 해제"는 다음과 같습니다.
Optimizer는 일부 예외를 제외한 대부분의 하위 쿼리를 제거할 수 있습니다.이러한 예외에는 ROWNUM 의사열, 집합 연산자 중 하나, 중첩 집계 함수 또는 하위 쿼리의 즉시 외부 쿼리 블록이 아닌 쿼리 블록에 대한 상관 참조가 포함된 계층적 하위 쿼리 및 하위 쿼리가 포함됩니다.
CASE 사용하기
CASE를 사용하면 Oracle이 다른 조건을 TRUE로 평가할 때만 기능을 평가하도록 강제할 수 있습니다.유감스럽게도 다른 절을 사용하여 인덱스를 사용하려면 코드를 복제해야 합니다.
SELECT * FROM players WHERE player_name LIKE '%K%' AND player_rank < 10 AND CASE WHEN player_name LIKE '%K%' AND player_rank < 10 THEN check_if_player_is_eligible(player_name) END > 1
이 과정에서 로넘 평가를 수반하지 않고 수행할 수 있는 NO_PUSH_PRED 힌트가 있습니다(어쨌든 좋은 트릭입니다)!
SELECT /*+NO_PUSH_PRED(v)*/*
FROM (
SELECT *
FROM players
WHERE player_name LIKE '%K%'
AND player_rank < 10
) v
WHERE check_if_player_is_eligible(player_name) > 1
일반적으로 특정한 실행 순서를 강요하지 않기를 원합니다.데이터나 쿼리가 변경되면 힌트와 트릭이 역효과를 낼 수 있습니다.Oracle이 올바른 결정을 내릴 수 있도록 유용한 메타데이터를 제공하는 것이 좋습니다.
이 경우에는 Associate STATRICS를 사용하여 함수에 대한 더 나은 최적화 통계를 제공할 수 있습니다.
예를 들어, 함수가 호출될 때마다 50개의 블록을 읽어야 하기 때문에 함수가 매우 느릴 경우:
associate statistics with functions
check_if_player_is_eligible default cost(1000 /*cpu*/, 50 /*IO*/, 0 /*network*/);
기본적으로 Oracle은 함수가 1/20의 행을 선택한다고 가정합니다.Oracle은 가능한 한 빨리 많은 행을 제거하기를 원하며, 선택도를 변경하면 먼저 실행될 가능성이 낮아집니다.
associate statistics with functions
check_if_player_is_eligible default selectivity 90;
그러나 이것은 몇 가지 다른 문제를 야기합니다.가능한 모든 조건에 대해 선택 항목을 선택해야 합니다. 90%가 항상 정확한 것은 아닙니다.IO 비용은 가져온 블록의 수이지만 CPU 비용은 "사용된 기계 명령"입니다. 정확히 무엇을 의미합니까?
Oracle Data Cartridge Extensible Optimizer를 사용하여 통계를 사용자 정의할 수 있는 보다 향상된 방법이 있습니다.하지만 데이터 카트리지는 아마도 가장 어려운 Oracle 기능 중 하나일 것입니다.
플레이어 여부를 지정하지 않았습니다.player_name이(가) 고유하거나 고유하지 않습니다.그런 다음 데이터베이스가 결과 레코드 당 적어도 한 번은 함수를 호출해야 한다고 가정할 수 있습니다.
근데 만약에 선수라면.player_name은(는) 고유하지 않으므로 카운트다운(distinct 플레이어)을 최소화할 수 있습니다.player_name) 횟수입니다.Oracle Magazine에서 (Ask)Tom이 보여주듯이, 스칼라 하위 쿼리 캐시는 이를 위한 효율적인 방법입니다.
스칼라 하위 쿼리 캐시를 사용하려면 함수 호출을 하위 선택으로 래핑해야 합니다.
SELECT players.*
FROM players,
(select check_if_player_is_eligible(player.player_name) eligible) subq
WHERE player_name LIKE '%K%'
AND player_rank < 10
AND ROWNUM >= 1
AND subq.eligible = 1
원래 쿼리를 파생 테이블에 넣은 다음 파생 테이블의 where 절에 추가 술어를 놓습니다.
select *
from (
select *
from players
where player_name like '%K%
and player_rank<10
) derived_tab1
Where check_if_player_is_eligible(player_name) > 1;
언급URL : https://stackoverflow.com/questions/8428328/oracle-how-to-ensure-that-a-function-in-the-where-clause-will-be-called-only-a
'source' 카테고리의 다른 글
SQL에서 루프 내에서 테이블에 300번 삽입하려면 어떻게 해야 합니까? (0) | 2023.10.02 |
---|---|
WordPress의 사용자 지정 게시물 유형에 기능 추가 (0) | 2023.10.02 |
최대 절전 모드 자동 증가가 데이터베이스에 설정되지 않음 (0) | 2023.10.02 |
경로 변경 시 스크롤 위치를 재설정하는 방법은? (0) | 2023.10.02 |
문자열(PowerShell)의 HTML 특정 문자를 벗어나는 가장 좋은 방법은 무엇입니까? (0) | 2023.10.02 |