11
votes

Query la plus rapide pour vérifier l'existence d'une rangée à Oracle?

J'utilise Oracle et j'ai une très grande table. Je dois vérifier l'existence d'une ligne de remplacement de quelques critères simples. Quelle est la meilleure façon d'aller à ce sujet à l'aide de SQL simple?

Voici ma meilleure hypothèse, et bien que cela puisse s'avérer assez rapide à mes besoins, j'aimerais apprendre une manière canonique pour faire fondamentalement SQL Server's "Existe "En oracle: xxx

le nombre () serait alors retourné comme un booléen dans un autre niveau. Le point principal est que je veux que Oracle fasse le strict minimum pour cette requête - j'ai seulement besoin de savoir s'il y a des lignes correspondant aux critères.

et oui, ces colonnes seront très indexées. < / p>


0 commentaires

4 Réponses :


5
votes
DECLARE
        ex INT;
BEGIN
        BEGIN
                SELECT  NULL
                INTO    ex
                FROM    dual
                WHERE   1 = 1
                        AND rownum = 1;
                DBMS_OUTPUT.put_line('found');
        EXCEPTION
        WHEN no_data_found THEN
                DBMS_OUTPUT.put_line('not found');
        END;
END;

7 commentaires

Peut-être même un indice de premier_Rows? Optimizer devrait faire cela implicitement quand il voit le rownum = 1 Je pense. Sélectionnez / * + First_Rows (N) * / NULL


@ROBERT: Bien sûr que cela ne fera pas mal d'en ajouter un, mais cela ne fonctionne vraiment que dans des jointures (il rend l'optimiseur à préférer la boucle imbriquée sur Hash Rejoinks)


@Quassnoi: Je pensais que cela rend l'optimiseur 'Index Happy' aussi.


@ROBERT: Les index sont bons pour la boucle imbriquée mais pas toujours bonne pour les jointures de hasch. Dans ce sens, oui, le prémunt_rows utilise des boucles imbriquées qui utilisent à son tour des index. Mais pour une seule table de table, l'indice sera utilisé quand même: il n'ya aucun avantage d'utiliser un FullScan ici et l'optimiseur ne le considérera pas probablement même à moins que ce soit explicitement dit.


Le Rownum = 1 est suffisant pour que l'optimisateur choisisse un plan qui trouvera la première rangée dès que possible.


Pourquoi pas seulement utiliser existe-t-il? Oracle fera l'optimisation de Rownum = 1 pour vous.


Vous avez besoin d'une requête SELECT. Vous ne pouvez pas simplement utiliser si vous n'existe pas dans SQL Server



16
votes

Utilisation de Count (*) est ok si vous utilisez également ROWNUM = 1:

declare
   l_cnt integer;
begin
   select count(*)
   into   l_cnt
   from   x
   where  x.col_a = value_a 
   and    x.col_b = value_b
   and    rownum = 1;
end;


5 commentaires

@Tony - feriez-vous un compte (*) au lieu d'un existant? Pour moi, une existe semble plus naturelle, même si vous avez besoin de faire face à l'exception.


Voulez-vous dire "Select 1 de Dual où existe-t-il (...)"? Je ne le ferais pas, mais peut comprendre pourquoi certains le feraient. Ce qui est vraiment voulu être très naturel est une construction PL / SQL comme "si existe-t-il (sélectionnez ...) alors ..."!


Je suis paresseux ici en ne le testant pas moi-même, mais ne compterais pas (x_id) être plus rapide que le compte (), ou est-ce que l'interprétation SQL est suffisamment intelligente pour voir qu'il n'a pas vraiment besoin de se développer " / I> "?


Le nombre (*) est optimisé pour être aussi efficace que toute autre méthode.


FWIW: Expliquer le plan pour cela n'a montré aucune différence de coût entre le nombre (*) et Rownum = 1 contre l'approche existante pour un exemple simple.



1
votes
begin
select 'row DOES exist' 
  into ls_result
from dual
where exists (select null from x where x.col_a = value_a and x.col_b = value_b);
exception
when no_data_found then
  ls_result := ' row does NOT exist';
end;

0 commentaires

7
votes

Je pense que l'utilisation d'Exist donne une réponse plus naturelle à la question que d'essayer d'optimiser une requête de comptage en utilisant Rownum.

Laissez Oracle faire l'optimisation de Rownum pour vous. P>

create or replace function is_exists (
        p_value_a varchar2,
        p_value_b varchar2)
        return boolean
is

   v_exists varchar2(1 char);

begin

    begin
        select 'Y' into v_exists from dual
        where exists
            (select 1 from x where x.col_a = p_value_a and x.col_b = p_value_a);

    exception

        when no_data_found then

            v_exists := null;

    end;

    return v_exists is not null;

end is_exists;


0 commentaires