sql >> Database >  >> RDS >> Oracle

Probleem met Oracle-bindvariabelen die index niet correct gebruiken

Dit is eigenlijk een groter onderwerp, maar dit is de aanpak die volgens mij het gemakkelijkst te implementeren is en goed werkt. De truc is om dynamische SQL te gebruiken, maar het zo te implementeren dat je altijd hetzelfde aantal parameters doorgeeft (nodig), EN je laat Oracle kortsluiten als je geen waarde voor een parameter hebt (wat je mist in uw huidige aanpak). Bijvoorbeeld:

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;

Om te testen, voert u het gewoon uit. Bijvoorbeeld:

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

Op mijn systeem is de gebruikte tabel meer dan 100 mm rijen met een index op het nummerveld en het naamveld. Retourneert vrijwel direct. Houd er ook rekening mee dat je misschien geen select * wilt doen als je niet alle kolommen nodig hebt, maar ik ben een beetje lui en gebruik %rowtype voor dit voorbeeld.

Ik hoop dat dat helpt



  1. PostgreSQL Checkpoint-statistieken meten

  2. SQL UPDATE-instructie om twee waarden in twee rijen te wisselen

  3. Hoe dynamische Postgres voorbereide statements te maken in PHP

  4. SCD-type 1