Skip to Main Content
  • Questions
  • How do I declare a VARCHAR2 variable in PL/SQL?

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Matthias.

Asked: February 22, 2024 - 9:55 pm UTC

Last updated: March 05, 2024 - 2:19 pm UTC

Version: 19+

Viewed 1000+ times

You Asked

Hi all,

Here is my question:

DECLARE
    l_something VARCHAR2( --<- WHAT NOW?


Okay, that's not a good question. Please let me explain.
I understand that in Oracle SQL, memory or rather storage, is allocated dynamically for VC2 columns. But that's not the topic.

In PL/SQL I can think of two goals:
A: allocate as much memory as possibly needed, add that much load to the PGA, grant maximum efficiency to data changes
B: allocate as little memory as needed (dynamically), limit load on PGA, be okay with waiting for memory reallocation

If my thoughts up to this point are mistaken, please explain (and stop reading here).

Otherwise and assuming I understand when to use A over B (and vice versa) in my application, how can I ensure I'm getting the behavior I want?

In https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/tuning.htm#LNPLS01203 (that's 11g), I found this:

You might need to allocate large VARCHAR2 variables when you are not sure how big an expression result will be. You can conserve memory by declaring VARCHAR2 variables with large sizes, such as 32000, rather than estimating just a little on the high side, such as by specifying 256 or 1000. PL/SQL has an optimization that makes it easy to avoid overflow problems and still conserve memory. Specify a size of more than 4000 characters for the VARCHAR2 variable; PL/SQL waits until you assign the variable, then only allocates as much storage as needed.

In the PL/SQL docs for 19c I couldn't find anything like this. I did not take the time to read the whole document, so if it's there and I overlooked it, please tell me where to look, maybe (and stop reading here).

Also I'd totally understand the editor if he'd silently deleted that paragraph.
And yes, it's 2019 where I am, because time zones.

Given the 11g implementation is still up, does that mean I should

DECLARE
    l_something VARCHAR2(4001);
    l_or_something VARCHAR2(4001 CHAR); --^^??


whenever I plan to load data from my VC2 column into my variable?



and Chris said...

I'm a little confused by that paragraph. Though the important part is right at the end:

PL/SQL waits until you assign the variable, then only allocates as much storage as needed.

Is this true?

Let's test and see.

Let's create arrays for varchar2 data with different max lengths (1, 4000, & 32767). Then load the arrays with 1 million elements that are all the value "a".

create or replace function get_stat (p_stat in varchar2) return number as
  l_return  number;
begin
  select ms.value
  into   l_return
  from   v$mystat ms
  join   v$statname sn
  on     ms.statistic# = sn.statistic#
  and    sn.name = p_stat;
  return l_return;
end get_stat;
/

conn chris
set serveroutput on
declare
  type arr is table of varchar2(1)
    index by pls_integer;
  a   arr;
  mem pls_integer;
begin
  mem := get_stat('session pga memory');
  
  for i in 1 .. 1000000 loop
    a(i) := 'a';
  end loop;
 
  DBMS_OUTPUT.put_line(
    'Length 1: ' || (get_stat('session pga memory') - mem)
  );
end;
/
conn chris
set serveroutput on
declare
  type arr is table of varchar2(4000)
    index by pls_integer;
  a   arr;
  mem pls_integer;
begin
  mem := get_stat('session pga memory');
  
  for i in 1 .. 1000000 loop
    a(i) := 'a';
  end loop;
 
  DBMS_OUTPUT.put_line(
    'Length 4000: ' || (get_stat('session pga memory') - mem)
  );
end;
/
conn chris
set serveroutput on
declare
  type arr is table of varchar2(32767)
    index by pls_integer;
  a   arr;
  mem pls_integer;
begin
  mem := get_stat('session pga memory');
  
  for i in 1 .. 1000000 loop
    a(i) := 'a';
  end loop;
 
  DBMS_OUTPUT.put_line(
    'Length 32767: ' || (get_stat('session pga memory') - mem)
  );
end;
/


I ran the test several times and took the last results from each block to avoid any parsing effects.

If the above statement is true, they'll all use the same amount of memory. Running on 19.22 I see this output:

Length 1: 68026368
Length 4000: 68026368
Length 32767: 68026368


Identical memory usage!

So from a memory usage perspective what matters is the size of the data assigned; not the upper limit for the variables.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library