sql >> Database teknologi >  >> RDS >> Oracle

Problem med Oracle-bindingsvariabler, der ikke bruger indekset korrekt

Dette er virkelig et større emne, men det er den tilgang, som jeg synes er lettest at implementere og fungerer godt. Tricket er at bruge dynamisk SQL, men implementer det så du altid sender det samme antal parametre (nødvendigt), OG du tillader Oracle at kortslutte, når du ikke har en værdi for en parameter (det du mangler i din nuværende tilgang). For eksempel:

set serveroutput on
create or replace procedure test_param(p1 in number default null, p2 in varchar2 default null) as
  l_sql varchar2(4000);
  l_cur sys_refcursor;
  l_rec my_table%rowtype;
  l_ctr number := 0;
begin

  l_sql := 'select * from my_table where 1=1';
  if (p1 is not null) then
    l_sql := l_sql || ' and my_num_col = :p1';
  else
    -- short circuit for optimizer (1=1)
    l_sql := l_sql || ' and (1=1 or :p1 is null)';
  end if;

  if (p2 is not null) then
    l_sql := l_sql || ' and name like :p2';
  else
    -- short circuit for optimizer (1=1)
    l_sql := l_sql || ' and (1=1 or :p2 is null)';
  end if;

  -- show what the SQL query will be
  dbms_output.put_line(l_sql);

  -- note always have same param list (using)
  open l_cur for l_sql using p1,p2;

  -- could return this cursor (function), or simply print out first 10 rows here for testing
  loop
    l_ctr := l_ctr + 1;
    fetch l_cur
    into l_rec;
    exit when l_cur%notfound OR l_ctr > 10;

    dbms_output.put_line('Name is: ' || l_rec.name || ', Address is: ' || l_rec.address1);
  end loop;
  close l_cur;
end;

For at teste skal du blot køre det. For eksempel:

set serveroutput on
-- using 0 param
exec test_param();
-- using 1 param
exec test_param(123456789);
-- using 2 params
exec test_param(123456789, 'ABC%');

På mit system er den anvendte tabel over 100 mm rækker med et indeks på nummerfeltet og navnefeltet. Vender tilbage næsten øjeblikkeligt. Bemærk også, at du måske ikke ønsker at vælge *, hvis du ikke har brug for alle kolonner, men jeg er lidt doven og bruger %rowtype til dette eksempel.

Håber det hjælper



  1. ALTER TABLE-sætningen var i konflikt med CHECK-begrænsningen i SQL Server - SQL Server / TSQL Selvstudium, del 89

  2. mysql_fetch_array() forventer, at parameter 1 er et ressourceproblem

  3. Fejl ved sletning af database (kan ikke sende '.test\', fejlnr.:17)

  4. Opdel streng efter mellemrum og tegn som skilletegn i Oracle med regexp_substr