sql >> Databasteknik >  >> RDS >> Oracle

Problem med Oracle-bindningsvariabler som inte använder index korrekt

Det här är ett större ämne egentligen, men det här är det tillvägagångssätt som jag tycker är lättast att implementera och fungerar bra. Tricket är att använda dynamisk SQL, men implementera det så att du alltid skickar samma antal parametrar (behövs), OCH du tillåter Oracle att kortsluta när du inte har ett värde för en parameter (det du saknar i ditt nuvarande tillvägagångssätt). Till exempel:

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;

För att testa, kör det helt enkelt. Till exempel:

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å mitt system är tabellen som används över 100 mm rader med ett index på nummerfältet och namnfältet. Återkommer nästan omedelbart. Observera också att du kanske inte vill välja * om du inte behöver alla kolumner, men jag är lite lat och använder %rowtype för det här exemplet.

Hoppas det hjälper



  1. Hur INSTR() fungerar i MariaDB

  2. SQL Server:hur man imiterar Oracle Keep dense_rank-frågan?

  3. SQL UPPDATERING Syntax – Listad av DBMS

  4. Få fältvärdet med en markör