Skip to Main Content
  • Questions
  • How to calculate memory, occupied by agrerate functions ? (ORA-01467: sort key too long)

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Michael.

Asked: August 07, 2000 - 3:34 pm UTC

Last updated: October 12, 2011 - 12:05 pm UTC

Version: Oracle 8.0.5

Viewed 10K+ times! This question is

You Asked

I have ORA-01467: sort key too long
in query with a lot of max() functions ( about 70 max() ).

I know that there is a limit on the memory, occupied by agrerate functions : "the group-by expression and all of the non-distinct aggregates (e.g., sum, avg) need to fit within a single database block."

I think if I will shrink table names and field names
this occupied space will be less for expressions like this
Max(decode(ANALYSIS.ANALYSIS_NAME,'CRASH',RESULT.AVG_VALUE)),

But when I renamed the tables and the fields and have now :
Before Now
----------------------- -----
ANALYSIS.ANALYSIS_NAME A.N
RESULT.AVG_VALUE R.AVG
Max(decode(ANALYSIS.ANALYSIS_NAME,
'CRASH',RESULT.AVG_VALUE)) Max(decode(A.N,'CRASH',R.AVG))


the same ORA-01467 after the same number of max occured...

Question :
How to calculate the memory, occupied by agrerate functions ?
------------------------------------------------------------
Regards, Michael.

P.S.
Here is my SQL:

Select ITEM.ITEM_NAME,
Max(decode(ANALYSIS.ANALYSIS_NAME,'CRASH',RESULT.AVG_VALUE)),
Max(decode(ANALYSIS.ANALYSIS_NAME,'CRASH',RESULT.MIN_VALUE)),
Max(decode(ANALYSIS.ANALYSIS_NAME,'CRASH',RESULT.MAX_VALUE)),

Max(decode(ANALYSIS.ANALYSIS_NAME,'SPEED',RESULT.AVG_VALUE)),
Max(decode(ANALYSIS.ANALYSIS_NAME,'SPEED',RESULT.MIN_VALUE)),
Max(decode(ANALYSIS.ANALYSIS_NAME,'SPEED',RESULT.MAX_VALUE)) ,

Max(decode(ANALYSIS.ANALYSIS_NAME,'BREAK',RESULT.AVG_VALUE)),
Max(decode(ANALYSIS.ANALYSIS_NAME,'BREAK',RESULT.MIN_VALUE)),
Max(decode(ANALYSIS.ANALYSIS_NAME,'BREAK',RESULT.MAX_VALUE))
...
Max(...)
...

from ITEM, ANALYSIS, RESULT
where RESULT.ITEM_ID=ITEM.ITEM_ID
and RESULT.ANALYSIS_ID=ANALYSIS.ANALYSIS_ID
Group by ITEM.ITEM_NAME


and Tom said...


It is based on the data values -- not their names. Consider:

ops$tkyte@8i> create table t ( x varchar2(4000), y varchar2(4000), z varchar2(4000), a int );

Table created.

A sort key including all 4 fields here could be very large indeed -- 12,000 bytes in x,y,z alone and upto 22 bytes for the number

ops$tkyte@8i> insert into t values ( 'x', 'y', 'z', 1 );
1 row created.

ops$tkyte@8i> select x, y, z, sum(a)
2 from t
3 group by x, y, z
4 /

X Y Z SUM(A)
---------- ---------- ---------- ----------
x y z 1

But it is not necessarily a problem -- not until we get a really large row in there anyway:

ops$tkyte@8i> insert into t
2 values
3 ( rpad('*',4000,'*'),
4 rpad('*',4000,'*'),
5 rpad('*',4000,'*'), 2
6 );

1 row created.

ops$tkyte@8i> select x, y, z, sum(a)
2 from t
3 group by x, y, z
4 /
from t
*
ERROR at line 2:
ORA-01467: sort key too long

So, you see - its a function of the ACTUAL data that is in there -- not the names of the tables or columns or their maximum POTENTIAL length. Its 100% a function of their current, actual length

Rating

  (40 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

OraDoc missleading

Marc Blum, April 25, 2002 - 4:36 am UTC

Oradoc 8.1.7 states:

ORA-01467 sort key too long
Cause: A DISTINCT, GROUP BY, ORDER BY, or SET operation requires a sort key longer than that supported by Oracle. Either too many columns or too many group functions were specified in the SELECT statement.
Action: Reduce the number of columns or group functions involved in the
operation.

If I compare that to your response, I would say, the documentation is missleading und not really helpful.



ORA-01467: sort key too long

Kenneth, April 25, 2002 - 10:53 pm UTC

Though we know it only depends on the data size but not the column name, how to tackle it is not mentioned. If we resize the database block size, say from now 8k to 16k, we have to re-gen the database and the impact is very big. Is there any work around?

Tom Kyte
April 26, 2002 - 8:21 am UTC

In 9i, you can have databases with more then one block size. So, one solution is to use 9i. There you can have 2, 4, 8, 16 even 32k blocksizes in the same database.

Other then that -- the max sort key is a FUNCTION of the block size -- period. The only way to get a bigger max sort key is to get a bigger block size.

what the term SORT KEY mean

ajar bajar, June 11, 2002 - 5:55 pm UTC

in the context it has been used here..

is this because when group by multiple columns, we also sort using the concatanation of all those columns.

Why are we talking about the block size here..

Tom Kyte
June 11, 2002 - 7:07 pm UTC

As they provided in the question themselves:

...
I know that there is a limit on the memory, occupied by agrerate functions :
"the group-by expression and all of the non-distinct aggregates (e.g., sum,
avg) need to fit within a single database block."
.......

need to fit on a single block (actually, a fraction of the block). that is the sort key here.

Reader

A reader, June 11, 2002 - 11:32 pm UTC

Tom,

Is this similar to sort_write_buffer_size in earlier
versions which is a tunable parameter

Thanks

Tom Kyte
June 12, 2002 - 6:50 am UTC

No, not really.

Let me sum it up for your critique...

ajar bajar, June 12, 2002 - 10:25 am UTC

So when I execute a sql like

select a,b,c,b
from x,z
where conditions
group by abc

then columns a,b,c are concatanated and then grouped by , is that it ?

and such concatanation should fit within one oracle block, for example if the block size is 16k then the concatanation of a,b,c should be less than or equal to 16k

other wise it is going to return usethe ora-01467, is that what you are saying ?

Tom Kyte
June 12, 2002 - 6:15 pm UTC

yes and no, you have the group by columns, but not the aggregates.. all of the columns in the group by, plus the aggregates themselves (and they had 70 some of them)

never read about this limitation

A reader, June 12, 2002 - 7:24 pm UTC

so groupby columns + aggregrates should not exceed block size.

Why is grouby columns + aggregates called the sort key. Actually only the grooup by columns together should be the sort key . How does the aggregate get included in the sort key? Doesnt make much meaning..

You aggregate values based on the sort key which is a concatenation of the groupby columns . Isnt it ?

Can you give the link giving the documentation for the sort key too long limitation.

Thx

Tom Kyte
June 13, 2002 - 8:01 am UTC

</code> http://docs.oracle.com/docs/cd/A87860_01/doc/server.817/a76999/e900.htm#1656 <code>

and search for 1467

ORA-01467 sort key too long

Cause: A DISTINCT, GROUP BY, ORDER BY, or SET operation requires a sort key longer than that supported by Oracle. Either too many columns or too many group functions were specified in the SELECT statement.

Action: Reduce the number of columns or group functions involved in the operation.




Sort Key too long

Ik, February 13, 2003 - 7:58 pm UTC

Tom,
Iam getting the error - Sort key too long and when i reduce the number of columns in the query, the error does not appear.

My situation is like this -
I want to generate output in a cross tab format. I take in a comma separated list of values and generate cross tab data. The query is done such that it takes in a max of 20 comma separated values. I have 20 columns per record and it is populated based on the number of values i have in my list.
If i gave 'a,b,c,d', i populate just the first four columns per record. The remaining columns have NULL throughout. Yet, i get sort key too long error and when i remove 10 columns or so from the query this error disappears. Since you said that this error is a function of the data, iam wondering why removing NULL columns could make a difference.
FYI - Iam grouping by just one column which was a varchar and i changed that to a smaller key. Still the error persists.

Any info will be greatly appreciated. Thanks as always.

Tom Kyte
February 13, 2003 - 8:00 pm UTC

it is a function of the max the data could be...

it is a function of your blocksize (about 40% of the block size is the maximum sort key)

so -- it computes the max it *could possibly hit* and that is the sort key length it uses.

If you hit it -- there is no "workaround", short of using a bigger block.

Thank You

Ik, February 13, 2003 - 8:09 pm UTC

Tom,

woooh!...that was very fast. Thanks.

So would doing a SUBSTR on the columns help? Would that influence MAX sizing.

Tom Kyte
February 13, 2003 - 8:12 pm UTC

yes, it could -- as long as cursor_sharing was exact (so the db knows how big the substr is)

Sort Key Too long

Girish, September 19, 2003 - 3:13 am UTC

This solution provided by Tom was helpful for us.But he should have given alternate ways of doing the things to eschew errors
In our case we have no scope of doing any changes to database.

Tom Kyte
September 20, 2003 - 5:04 pm UTC

i can only give the alternate of "don't run that query" as there is no alternative if you have a sort key that is too long!

How can that be "too long" ???

A reader, April 08, 2004 - 2:23 pm UTC

1 select trim(substr(a.owner,1,30)) owner,
2 trim(substr(a.table_name,1,30)) table_name,
3 trim(substr(a.constraint_name,1,30)) constraint_name,
4 max(decode(position, 1, substr(column_name,1,30),NULL)) ||
5 max(decode(position, 2,', '||substr(column_name,1,30),NULL)) ||
6 max(decode(position, 3,', '||substr(column_name,1,30),NULL)) ||
7 max(decode(position, 4,', '||substr(column_name,1,30),NULL)) ||
8 max(decode(position, 5,', '||substr(column_name,1,30),NULL)) ||
9 max(decode(position, 6,', '||substr(column_name,1,30),NULL)) ||
10 max(decode(position, 7,', '||substr(column_name,1,30),NULL)) ||
11 max(decode(position, 8,', '||substr(column_name,1,30),NULL)) ||
12 max(decode(position, 9,', '||substr(column_name,1,30),NULL)) ||
13 max(decode(position,10,', '||substr(column_name,1,30),NULL)) ||
14 max(decode(position,11,', '||substr(column_name,1,30),NULL)) ||
15 max(decode(position,12,', '||substr(column_name,1,30),NULL)) ||
16 max(decode(position,13,', '||substr(column_name,1,30),NULL)) ||
17 max(decode(position,14,', '||substr(column_name,1,30),NULL)) ||
18 max(decode(position,15,', '||substr(column_name,1,30),NULL)) ||
19 max(decode(position,16,', '||substr(column_name,1,30),NULL)) columns
20 from dba_cons_columns a, dba_constraints b
21 where a.owner = b.owner
22 and a.constraint_name = b.constraint_name
23 and b.constraint_type = 'R'
24 group by trim(substr(a.owner,1,30)),
25 trim(substr(a.table_name,1,30)),
26* trim(substr(a.constraint_name,1,30))
SYS@ORAPRD> /
trim(substr(a.constraint_name,1,30))
*
ERROR at line 26:
ORA-01467: sort key too long


Tom Kyte
April 08, 2004 - 3:41 pm UTC

what is your block size -- aggregates as well as group by columns are needed to be taken into consideration here.

Please see this IT is very simple for you but important for me

GP, April 09, 2004 - 2:01 pm UTC

I am new oracle user using PL SQL from last 4 months.
I am using a simple query

select P.DT, sum(c) from AA
where date = (select max(date) DT from AA
where date < date 1
and condition.....)P
where Date = p.DT
and conditionss......

My procedure has this Query and it took like 6 hrs
for like 50,000 records, then I saw there were no indexes
I created the indexes which reduced the calculation to
45 mins for 1 day of calculation
then the above query I made two seperate queries and
it time reduced to 30 mins.
now when actually this process is running for a month it takes a lot of time.
and In the explain plan I saw it takes a lot of time
in (select max(date) from AA......).
Can you please provide mw with some help.

Thanks a lot.
GP


Tom Kyte
April 09, 2004 - 4:16 pm UTC

stop doing things procedurally, looks like you are doing that query in a loop (if you are doing it 50,000 times). do it in the query that you are looping over in the first place!!!!!!




Tom i don't agree with your comment

A reader, March 29, 2005 - 4:10 pm UTC

we are getting sort key too long when we are trying to wrap 38 fields of lineitem table and summarize them
inside the query uses group by and decode

i don;t understand relationship between block size and sort key; if the sort size exceeds block size why can't oracle get another block


Tom Kyte
March 29, 2005 - 5:04 pm UTC

what don't you agree with?

you seem to have reproduced the issue yourself.

Using ROWID to solve 'sort key too long' error

Praveen, October 27, 2005 - 9:12 am UTC

Tom,

SELECT * FROM (
select t1.id, t2.COL1, t2.COL2, t2.COL3,
row_number() over (partition by t1.id, t2.code, t2.srlno --to avoid duplicate records in T2.
order by t1.id, t2.code, t2.srlno) rn
from Table1 t1, Table2 t2
where t2.code = t1.code
and t2.srlno = t1.srlno
)
WHERE rn = 1;

I was happily executing this query until I added 37 more columns
(COL4, COL5...COL40) in the inner query when I got
'ORA-01467: sort key too long' error. (Oracle 10g)

To get around I used the rowid of the Table2.

select t1.id, t2.COL1, t2.COL2, t2.COL3,.........., t2.COL40
from (
select * from (
select t2.rowid rid, --ROWID needed because of "SORT KEY TOO LONG" error.
t1.id id, t1.code code, t1.srlno srlno,
row_number() over (partition by t1.frlnkid, t2.code, t2.srlno
order by t1.frlnkid, t2.code, t2.srlno) rn
from Table1 t1, Table2 t2
where t2.code) = t1.code
and t2.srlno = t1.srlno
) where rn = 1
) t1, Table2 t2
where t1.rid = t2.rowid;

Now it stalls. Is there any better method to get around ORA-01467 error?

Best regards...


Tom Kyte
October 27, 2005 - 1:06 pm UTC

what is your version
what is your blocksize

and can you help me reproduce, I tried in 8i..10gr2:

ops$xp8i\tkyte@ORA8IR3W> drop table t;

Table dropped.

ops$xp8i\tkyte@ORA8IR3W>
ops$xp8i\tkyte@ORA8IR3W> declare
  2      l_cols long;
  3  begin
  4      for i in 1 .. 200
  5      loop
  6          l_cols := l_cols || ', object_name x' || i;
  7      end loop;
  8      execute immediate '
  9  create table t
 10  as
 11  select all_objects.* ' || l_cols || ', rpad( ''*'', 1000, ''*'' ) data
 12    from all_objects
 13   where rownum <= 1000';
 14  end;
 15  /

PL/SQL procedure successfully completed.

ops$xp8i\tkyte@ORA8IR3W> select count(*) from t;

  COUNT(*)
----------
      1000

ops$xp8i\tkyte@ORA8IR3W>
ops$xp8i\tkyte@ORA8IR3W> select *
  2    from ( select t.*, row_number() over (partition by owner order by created) rn
  3             from t
  4         )
  5   where rn = 1;

OWNER                          OBJECT_NAME
.... 

Getting ORA-01467: sort key too long for STRAGG

David, January 05, 2006 - 7:35 pm UTC

Hi Tom,

I use 9.2.0.6 with 8k block size.

STRAGG is your (I beleive) string aggregation function

The SQL with 2 stragg function expressions is running fine, with 3 it gives:
"ORA-01467: sort key too long"

select SESSION_ID
,substr(straggs(distinct X_ID),1,128) as X_ID_LST
,substr(straggs(distinct Y_ID),1,128) as Y_ID_LST
,substr(straggs(distinct Z_ID),1,128) as Z_ID_LST
from pvt_tmp_session_id ts JOIN dts_session_event sse ON (ts.session_id=sse.session_id)
where rownum<=100
GROUP BY A,B,C;


I tried to implement the VARCHAR2(128) version of stragg straggs(mall), but it still having the same issue.

The interesting thing is that it gives the error even when the underlying temp table pvt_tmp_session_id is empty
(and the join doesn't yeld any records).

The wrapping into the "substr" or cast(straggs(x_ID) as varchar2(128)) doesn't help either..

Please see the straggs DDL below:

create or replace type vcArrays as table of varchar2(128)
/

create or replace type string_agg_types as object
(
data vcArrays,
static function
ODCIAggregateInitialize(sctx IN OUT string_agg_types )
return number,

member function
ODCIAggregateIterate(self IN OUT string_agg_types ,
value IN varchar2 )
return number,

member function
ODCIAggregateTerminate(self IN string_agg_types,
returnValue OUT varchar2,
flags IN number)
return number,

member function
ODCIAggregateMerge(self IN OUT string_agg_types,
ctx2 IN string_agg_types)
return number
);
/


create or replace type body string_agg_types
is

static function ODCIAggregateInitialize(sctx IN OUT string_agg_types)
return number
is
begin
sctx := string_agg_types( vcArrays() );
return ODCIConst.Success;
end;

member function ODCIAggregateIterate(self IN OUT string_agg_types,
value IN varchar2 )
return number
is
begin
data.extend;
data(data.count) := value;
return ODCIConst.Success;
end;

member function ODCIAggregateTerminate(self IN string_agg_types,
returnValue OUT varchar2,
flags IN number)
return number
is
l_data varchar2(128);
begin
for x in ( select column_value from TABLE(data) order by 1 )
loop
l_data := l_data || ',' || x.column_value;
end loop;
returnValue := ltrim(l_data,',');
return ODCIConst.Success;
end;

member function ODCIAggregateMerge(self IN OUT string_agg_types,
ctx2 IN string_agg_types)
return number
is
begin -- not really tested ;)
for i in 1 .. ctx2.data.count
loop
data.extend;
data(data.count) := ctx2.data(i);
end loop;
return ODCIConst.Success;
end;


end;
/

CREATE or replace
FUNCTION straggs(input varchar2 )
RETURN varchar2
PARALLEL_ENABLE AGGREGATE USING string_agg_types;
/


Tom Kyte
January 06, 2006 - 1:12 pm UTC

your blocksize is?
your tables look like


I've got the code for stragg already - but nothing else to reproduce or look at the issue with?


ops$tkyte@ORA10GR2> create table t ( a char(2000), b char(2000), c char(2000), x_id number, y_id number, z_id number, session_id number  );

Table created.

ops$tkyte@ORA10GR2>
ops$tkyte@ORA10GR2> select session_id, stragg(distinct x_id), stragg(distinct y_id), stragg(distinct z_id)
  2    from t
  3   group by session_id, a, b, c;

no rows selected
 

8K - ORA-01467

David, January 06, 2006 - 5:59 pm UTC

Tom,
8k as I mentioned above.

Your example does produce the error on my instance:

select * from v$version;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.5.0 - Production
PL/SQL Release 9.2.0.5.0 - Production
CORE 9.2.0.6.0 Production
TNS for Linux: Version 9.2.0.5.0 - Production
NLSRTL Version 9.2.0.5.0 - Production

show parameter db_block_size

NAME TYPE VALUE
------------------------------------ -------------------------------- ------------------------------
db_block_size integer 8192

create table t
( a char(2000), b char(2000), c char(2000), x_id number, y_id number, z_id number, session_id number );

Table created.

Elapsed: 00:00:00.19
DATA_OWNER_DW@AWDEV1.ADPROFILE.NET>
DATA_OWNER_DW@AWDEV1.ADPROFILE.NET> select session_id, stragg(distinct x_id), stragg(distinct y_id), stragg(distinct z_id)
2 from t
3 group by session_id, a, b, c;
select session_id, stragg(distinct x_id), stragg(distincty_id), stragg(distinct z_id)
*
ERROR at line 1:
ORA-01467: sort key too long


Thank you for your time!
David

Tom Kyte
January 06, 2006 - 7:12 pm UTC

ops$tkyte@ORA9IR2> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.6.0 - Production
PL/SQL Release 9.2.0.6.0 - Production
CORE    9.2.0.6.0       Production
TNS for Linux: Version 9.2.0.6.0 - Production
NLSRTL Version 9.2.0.6.0 - Production

ops$tkyte@ORA9IR2> show parameter block_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_size                        integer     8192

ops$tkyte@ORA9IR2> select session_id, stragg(distinct x_id), stragg(distinct y_id), stragg(distinct z_id)
  2  from t
  3  group by session_id, a, b, c;

no rows selected


I cannot reproduce... (9204 or 9206)

what non-default init.ora's do you have?
 

ORA-01467 on 9.2.0.5 and 9.2.0.6

David, January 09, 2006 - 2:49 pm UTC

I also get it on 9.2.0.5 (SUSE Linux)

our 10G instance doesn't have the issue...

Starting up ORACLE RDBMS Version: 9.2.0.5.0.
System parameters with non-default values:
processes = 400
sessions = 1000
timed_statistics = TRUE
shared_pool_size = 201326592
large_pool_size = 33554432
java_pool_size = 0
nls_date_format = YYYY-MM-DD HH24:MI:SS
nls_timestamp_format = YYYY-MM-DD HH24:MI:SS.FF6
nls_timestamp_tz_format = YYYY-MM-DD HH24:MI:SS.FF6TZH
db_block_size = 8192
db_cache_size = 1073741824
compatible = 9.2.0.0.0
log_buffer = 1048576
log_checkpoint_interval = 1000000
log_checkpoint_timeout = 3600
db_files = 200
db_file_multiblock_read_count= 16
fast_start_mttr_target = 3600
undo_management = AUTO
undo_tablespace = UNDOTBS2
undo_retention = 10800
remote_login_passwordfile= NONE
db_domain = adprofile.net
instance_name = awdev1
service_names = awdev1
job_queue_processes = 1
cursor_sharing = similar
hash_join_enabled = TRUE
hash_area_size = 1048576
background_dump_dest = /opt/oracle/admin/awdev1/bdump
user_dump_dest = /opt/oracle/admin/awdev1/udump
core_dump_dest = /opt/oracle/admin/awdev1/cdump
audit_trail = DB
sort_area_size = 1048576
db_name = awdev1
open_cursors = 300
sql_trace = TRUE
star_transformation_enabled= TRUE
parallel_adaptive_multi_user= TRUE
parallel_threads_per_cpu = 3
parallel_automatic_tuning= TRUE
query_rewrite_enabled = TRUE
query_rewrite_integrity = STALE_TOLERATED
pga_aggregate_target = 1073741824
aq_tm_processes = 1

Any workaround would be appeciated :)
Thank you!
David
Thank you


Tom Kyte
January 09, 2006 - 3:02 pm UTC

I cannot suggest workaround unless and until I can reproduce - and I cannot.

I'll have to refer you to support, they can set some events to get further diagnostics on this.

Thanks!

David, January 09, 2006 - 3:24 pm UTC


Stanislav, April 24, 2006 - 9:47 pm UTC

Tom, there is something wrong with oracle the way it being done and sort key too long problem. if i had knew aggregate functions have 64k constraint limitations i would have designed them myself rather than use oracle versions. this is a straightforward bug and oracle should have fixed it long ago rather than forcing block size change which is not feasible in production db

instead of adding "java" to the database

A reader, May 12, 2006 - 3:02 pm UTC

instead of adding "java" to the database oracle could have fix this !!!

Please explain this behavior

A reader, May 30, 2006 - 9:13 am UTC

I'm hitting the ORA-01467: sort key too long error, but the surrounding information doesn't make sense to me.

I have a 4k block size.

I am trying to pivot rows to columns using the MAX(DECODE( construct with an analytic query. I really want to allow for 200 columns with pairs of the containerid, and container quantity separated by a comma.

In our process, we are looking to see if there is a stateprescription that exists and is made up of a pre-existing combination of containerids and quantities. There can be up to 10 statecheckcontainers on a statecheck, and we don't give out more than 20 checks ever for a prescription. (20*10=200)

A person is passing me a string of these containerids and containerquantities, and using SQL only, I have to see if the combination already exists.

Here is the query I came up with help from your knowledge:

select stateprescriptionid
, max(decode(nvl(rn,0),1, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),2, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),3, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),4, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),5, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),6, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),7, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),8, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),9, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),10,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),11,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),12,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),13,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),14,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),15,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),16,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),17,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),18,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),19,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),20,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),21,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),22,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),23,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),24,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),25,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),26,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),27,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),28,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),29,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),30,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),31,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),32,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),33,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),34,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),35,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),36,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),37,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),38,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),39,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),40,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),41,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),42,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),43,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),44,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),45,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),46,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),200,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) containerids_quantities
from (select stateprescriptionid
, containerid
, containerquantity
, row_number () over (partition by stateprescriptionid
order by containerid, containerquantity
) rn
from statecheckcontainer t1 join statecheck t2 on t1.statecheckid = t2.statecheckid
join stateprescription t3 on t2.stateprescriptionid = t3.stateprescriptionid
)
group by stateprescriptionid
;

Here is the error:

join stateprescription t3 on t2.stateprescriptionid = t3.stateprescriptionid
*
ERROR at line 57:
ORA-01467: sort key too long

So the sort key is the stateprescriptionid.
The odd thing is, if I remove the 47th group by, the query works, and I get back data that looks like this:

STATEPRESCRIPTIONID | CONTAINERIDS_QUANTITIES
=================== | ========================
1 | 85,66
4 | 23,3144,24
6 | 8,2
8 | 23,145,184,16
9 | 143,9
10 | 11,211,223,223,245,184,1684,1699,1134,36
12 | 23,245,195,299,1134,36
13 | 106,2144,16
22 | 33,633,7
31 | 9,19,19,145,145,161,182,182,182,2134,36
32 | 23,245,184,1696,2134,36
40 | 23,123,245,145,161,166,166,176,2684,4896,296,299,1134,36


Exactly what I want in format, just not enough columns.

So the two really wierd things are:

1) The 47th group by breaks it, but there are no other combinations of the containerids and containerquantities other than what is shown when the 46 group bys execute successfully! In other words, all the combinations of containerids and containerquantities return successfully when only 46 pivots execute, but when I try to tack on columns that *should be empty*, I get the error. I have tried to trim the stateprescriptionid column and the containerid and containerquantity columns to ensure "no bytes exist there", but that didn't work.

2) The other really strange part is, if I copy all the stateprescriptionids into MS word and do a count of the number of characters with no spaces, it comes out to 4758.
That is more than my blocksize is set to?? The data contained in the concatination of those two columns far exceeds my 4k block size?

Your example at the start of this thread used multiple large columns for a sort key. Mine is only a single number field. The error, and what you stated seems to say something different than this article in metalink:

</code> https://metalink.oracle.com/metalink/plsql/f?p=130:14:5534377224413130933::::p14_database_id,p14_docid,p14_show_header,p14_show_help,p14_black_frame,p14_font:NOT,18870.1,1,0,1,helvetica <code>

which says:

"Most notably, GROUP BY operations still require the GROUP BY columns and all non distinct data (aggregates) to fit into a single Oracle block (minus overhead)."

indicating that it's not the sort key itself that needs to fit, but the stuff in the group bys.

How can I use some simple logic and math to figure out what I need to do here?


Thanks much!!


Tom Kyte
May 30, 2006 - 9:39 am UTC

the aggregates need to fit there as well.

sum up all of the decoded values and you'll get the rest of your sort key.

Ok

A reader, May 30, 2006 - 9:58 am UTC

But the issue is, the amount of data returned by the 46 group by's that executes successfully far exceeds the 4k block size I have. I get back 1272 records from that query, each of which has a stateprescriptionid and a combination of those containerids and containerquantities separated by a comma. All told, the data returned by that query both stateprescriptionid and all group bys together without spaces is 25,385 bytes?

How does that make sense with a 4k block size?



PS

A reader, May 30, 2006 - 10:01 am UTC

I executed the query in an 8k blocksize db, and the results are near liniar. I was able to run with 96 group bys.

What do you think of making my db_block_size 32k, and then creating 4k blocksize tablespaces for my OLTP tables?

Thanks very much.

Tom Kyte
May 30, 2006 - 10:13 am UTC

I think that is a horrible idea.

It is a function of the number of aggregates you have there (they are part of your sort key, as you have just "shown" with the 4/8k example)

Using multiple block sizes would just not be a good idea for this.

containerid||','||containerquantity - can you make that "shorter" (eg: is one of the attributes "oversize" - can you substr shorter)

or maybe you can you use a collection instead.

got version?

Ok

A reader, May 30, 2006 - 10:44 am UTC

I'm using 9.2.0.4.0.

I cannot make the combination any shorter. As I stated though, the columns beyond 46 are *empty*. That's what's confusing me. There is nothing in them. In other words, every possible combination is handled within the first 46 group bys. So how does the addition of group bys that operate on empty data contribute to the problem?

Also, if you would please address the issue of how the data adds up to over 25k for the 46 group bys, yet is executed? There must be a flaw in my correlation of what needs to fit in 4k....??

Look at my original posting. The data returned that you see there is a representative sample of what I get back, and I get 1272 records returned. That sizing of that data is far more than 4k, which is what is not making sense.

Could you give some more detail why it would be a horrible idea to use the 32k block size at database creation time and then a 4k cache and 4k tablespace blocksize for my application schema? That is a feature offered by the database, and my issue here is directly related to an Oracle limitation that the db_block_size established at the time of database creation limits my ability to use many aggregate functions.

Thank very much for your attention.

Tom Kyte
May 30, 2006 - 10:58 am UTC

it is the "possible length", there need not be a first column worth of data.

the problem is based on an implementation issue here, the length is the length and it is a function of the block size.

Using a 32k blocksize and then 4k here and there - ugh, management issues. Multiple buffer caches, defeats automatic memory management in current releases, has people 2 years from now asking "why did we do this?"

Ok

A reader, May 30, 2006 - 12:32 pm UTC

Can you explicitly tell me what in my return data set is overflowing the 4k blocksize limit? I still do not see the correlation here based on what I explained earlier.

I do understand now about the different block size issue. Thanks for that.



Tom Kyte
May 30, 2006 - 12:35 pm UTC

when you go from 4k to 8k - you doubled the amount you could do right? There is the correlation.

It isn't just 4k, it is a limitation based on the size of the block.

Right

A reader, May 30, 2006 - 12:45 pm UTC

I see that point, but can you tell me what data, (if I add up all the bytes is causing the error to occur?

i.e. What, if you add up the bytes in this query output overflows the block size?

STATEPRESCRIPTIONID | CONTAINERIDS_QUANTITIES
=================== | ========================================================
1 | 85,66
4 | 23,3144,24
6 | 8,2
8 | 23,145,184,16
9 | 143,9
10 | 11,211,223,223,245,184,1684,1699,1134,36
12 | 23,245,195,299,1134,36
13 | 106,2144,16
22 | 33,633,7
31 | 9,19,19,145,145,161,182,182,182,2134,36
32 | 23,245,184,1696,2134,36
40 | 23,123,245,145,161,166,166,176,2684,4896,296,299,1134,36
51 | 1,6
.
.
.
1272 rows worth


Also, where is some good material I can read about that would help me really determine the optimum block size for my application.

Thanks much

Tom Kyte
May 30, 2006 - 1:55 pm UTC

8k is likely the "best" these days - for most everything.

There is an internal implementation restriction, that varies by release (pretty much always on the "increase")


ops$tkyte@ORA734> create table t ( x varchar2(&1), y varchar2(&1) );
Enter value for 1: 750
Enter value for 1: 750
old   1: create table t ( x varchar2(&1), y varchar2(&1) )
new   1: create table t ( x varchar2(750), y varchar2(750) )
 
Table created.
 
ops$tkyte@ORA734> select value from v$parameter where name like '%block_s%';
 
VALUE
-------------------------------------------------------------------------------
8192
 
ops$tkyte@ORA734>
ops$tkyte@ORA734> select max(decode(rownum,0,x)), max(decode(rownum,1,x)), max(decode(rownum,2,x)), max(decode(rownum,3,x)),
  2             max(decode(rownum,4,x)), max(decode(rownum,5,x)), max(decode(rownum,6,x)), max(decode(rownum,7,x)),
  3         max(decode(rownum,8,x)), max(decode(rownum,9,x)), max(decode(rownum,10,x)), max(decode(rownum,11,x)),
  4         max(decode(rownum,12,x)), max(decode(rownum,13,x)), max(decode(rownum,14,x)), max(decode(rownum,15,x)),
  5         max(decode(rownum,16,x)), max(decode(rownum,17,x)), max(decode(rownum,18,x)), max(decode(rownum,19,x)),
  6         max(decode(rownum,20,x)), max(decode(rownum,21,x)), max(decode(rownum,22,x)), max(decode(rownum,23,x)),
  7         max(decode(rownum,24,x)), max(decode(rownum,25,x)), max(decode(rownum,26,x)), max(decode(rownum,27,x)),
  8         max(decode(rownum,28,x)), max(decode(rownum,29,x)), max(decode(rownum,30,x)), max(decode(rownum,31,x)),
  9         max(decode(rownum,32,x)), max(decode(rownum,33,x)), max(decode(rownum,34,x)), max(decode(rownum,35,x)),
 10         max(decode(rownum,36,x)), max(decode(rownum,37,x)), max(decode(rownum,38,x)), max(decode(rownum,39,x)),
 11         max(decode(rownum,40,x)), max(decode(rownum,41,x)), max(decode(rownum,42,x)), max(decode(rownum,43,x)),
 12         max(decode(rownum,44,x)), max(decode(rownum,45,x)), max(decode(rownum,46,x)), max(decode(rownum,47,x)),
 13         max(decode(rownum,48,x)), max(decode(rownum,49,x))
 14    from t
 15   group by y;
  from t
       *
ERROR at line 14:
ORA-01467: sort key too long


ops$tkyte@ORA817DEV> create table t ( x varchar2(&1), y varchar2(&1) );
Enter value for 1: 750
Enter value for 1: 750
old   1: create table t ( x varchar2(&1), y varchar2(&1) )
new   1: create table t ( x varchar2(750), y varchar2(750) )
 
Table created.
 
ops$tkyte@ORA817DEV> select value from v$parameter where name like '%block_s%';
 
VALUE
-------------------------------------------------------------------------------
8192
 
ops$tkyte@ORA817DEV>
ops$tkyte@ORA817DEV> select max(decode(rownum,0,x)), max(decode(rownum,1,x)), max(decode(rownum,2,x)), max(decode(rownum,3,x)),
  2             max(decode(rownum,4,x)), max(decode(rownum,5,x)), max(decode(rownum,6,x)), max(decode(rownum,7,x)),
  3         max(decode(rownum,8,x)), max(decode(rownum,9,x)), max(decode(rownum,10,x)), max(decode(rownum,11,x)),
  4         max(decode(rownum,12,x)), max(decode(rownum,13,x)), max(decode(rownum,14,x)), max(decode(rownum,15,x)),
  5         max(decode(rownum,16,x)), max(decode(rownum,17,x)), max(decode(rownum,18,x)), max(decode(rownum,19,x)),
  6         max(decode(rownum,20,x)), max(decode(rownum,21,x)), max(decode(rownum,22,x)), max(decode(rownum,23,x)),
  7         max(decode(rownum,24,x)), max(decode(rownum,25,x)), max(decode(rownum,26,x)), max(decode(rownum,27,x)),
  8         max(decode(rownum,28,x)), max(decode(rownum,29,x)), max(decode(rownum,30,x)), max(decode(rownum,31,x)),
  9         max(decode(rownum,32,x)), max(decode(rownum,33,x)), max(decode(rownum,34,x)), max(decode(rownum,35,x)),
 10         max(decode(rownum,36,x)), max(decode(rownum,37,x)), max(decode(rownum,38,x)), max(decode(rownum,39,x)),
 11         max(decode(rownum,40,x)), max(decode(rownum,41,x)), max(decode(rownum,42,x)), max(decode(rownum,43,x)),
 12         max(decode(rownum,44,x)), max(decode(rownum,45,x)), max(decode(rownum,46,x)), max(decode(rownum,47,x)),
 13         max(decode(rownum,48,x)), max(decode(rownum,49,x))
 14    from t
 15   group by y;
 
no rows selected

<b>but...</b>

ops$tkyte@ORA817DEV> create table t ( x varchar2(&1), y varchar2(&1) );
old   1: create table t ( x varchar2(&1), y varchar2(&1) )
new   1: create table t ( x varchar2(2000), y varchar2(2000) )
 
Table created.
 
ops$tkyte@ORA817DEV> select value from v$parameter where name like '%block_s%';
 
VALUE
-------------------------------------------------------------------------------
8192
 
ops$tkyte@ORA817DEV>
ops$tkyte@ORA817DEV> select max(decode(rownum,0,x)), max(decode(rownum,1,x)), max(decode(rownum,2,x)), max(decode(rownum,3,x)),
  2             max(decode(rownum,4,x)), max(decode(rownum,5,x)), max(decode(rownum,6,x)), max(decode(rownum,7,x)),
  3         max(decode(rownum,8,x)), max(decode(rownum,9,x)), max(decode(rownum,10,x)), max(decode(rownum,11,x)),
  4         max(decode(rownum,12,x)), max(decode(rownum,13,x)), max(decode(rownum,14,x)), max(decode(rownum,15,x)),
  5         max(decode(rownum,16,x)), max(decode(rownum,17,x)), max(decode(rownum,18,x)), max(decode(rownum,19,x)),
  6         max(decode(rownum,20,x)), max(decode(rownum,21,x)), max(decode(rownum,22,x)), max(decode(rownum,23,x)),
  7         max(decode(rownum,24,x)), max(decode(rownum,25,x)), max(decode(rownum,26,x)), max(decode(rownum,27,x)),
  8         max(decode(rownum,28,x)), max(decode(rownum,29,x)), max(decode(rownum,30,x)), max(decode(rownum,31,x)),
  9         max(decode(rownum,32,x)), max(decode(rownum,33,x)), max(decode(rownum,34,x)), max(decode(rownum,35,x)),
 10         max(decode(rownum,36,x)), max(decode(rownum,37,x)), max(decode(rownum,38,x)), max(decode(rownum,39,x)),
 11         max(decode(rownum,40,x)), max(decode(rownum,41,x)), max(decode(rownum,42,x)), max(decode(rownum,43,x)),
 12         max(decode(rownum,44,x)), max(decode(rownum,45,x)), max(decode(rownum,46,x)), max(decode(rownum,47,x)),
 13         max(decode(rownum,48,x)), max(decode(rownum,49,x))
 14    from t
 15   group by y;
  from t
       *
ERROR at line 14:
ORA-01467: sort key too long



ops$tkyte@ORA10GR2> create table t ( x varchar2(&1), y varchar2(&1) );
old   1: create table t ( x varchar2(&1), y varchar2(&1) )
new   1: create table t ( x varchar2(2000), y varchar2(2000) )
 
Table created.
 
ops$tkyte@ORA10GR2> select value from v$parameter where name like '%block_s%';
 
VALUE
-------------------------------------------------------------------------------
8192
 
ops$tkyte@ORA10GR2>
ops$tkyte@ORA10GR2> select max(decode(rownum,0,x)), max(decode(rownum,1,x)), max(decode(rownum,2,x)), max(decode(rownum,3,x)),
  2         max(decode(rownum,4,x)), max(decode(rownum,5,x)), max(decode(rownum,6,x)), max(decode(rownum,7,x)),
  3         max(decode(rownum,8,x)), max(decode(rownum,9,x)), max(decode(rownum,10,x)), max(decode(rownum,11,x)),
  4         max(decode(rownum,12,x)), max(decode(rownum,13,x)), max(decode(rownum,14,x)), max(decode(rownum,15,x)),
  5         max(decode(rownum,16,x)), max(decode(rownum,17,x)), max(decode(rownum,18,x)), max(decode(rownum,19,x)),
  6         max(decode(rownum,20,x)), max(decode(rownum,21,x)), max(decode(rownum,22,x)), max(decode(rownum,23,x)),
  7         max(decode(rownum,24,x)), max(decode(rownum,25,x)), max(decode(rownum,26,x)), max(decode(rownum,27,x)),
  8         max(decode(rownum,28,x)), max(decode(rownum,29,x)), max(decode(rownum,30,x)), max(decode(rownum,31,x)),
  9         max(decode(rownum,32,x)), max(decode(rownum,33,x)), max(decode(rownum,34,x)), max(decode(rownum,35,x)),
 10         max(decode(rownum,36,x)), max(decode(rownum,37,x)), max(decode(rownum,38,x)), max(decode(rownum,39,x)),
 11         max(decode(rownum,40,x)), max(decode(rownum,41,x)), max(decode(rownum,42,x)), max(decode(rownum,43,x)),
 12         max(decode(rownum,44,x)), max(decode(rownum,45,x)), max(decode(rownum,46,x)), max(decode(rownum,47,x)),
 13         max(decode(rownum,48,x)), max(decode(rownum,49,x))
 14    from t
 15   group by y;
 
no rows selected


 

I see

A reader, May 30, 2006 - 4:01 pm UTC

That's good information.

Based on my situation, I need 200 columns, therefore the only blocksize that would work for me would be 16k. That will get me ~ 190 columns max.

How bad would the inefficiency be in an OLTP application with a 16k blocksize?

What are the main issues with a large block size and small reads/writes?

Is it just a larger SGA/inefficient use of I/O? i.e. Lot's of wasted cpu/disk effort?

Thanks






Tom Kyte
May 30, 2006 - 6:52 pm UTC

"i need 200 columns"
"16k gets me 190"

so how would 16k *work* for you.



A reader, May 31, 2006 - 7:49 am UTC

<grin>

Good catch. My clarity was lingering. I have over-estimated the number of columns I need by a favorable amount; therefore, 190+ columns would be acceptible. What that translates to in business language is I could be guaranteed to offer 19 checks with 10 containers on each.

We should never hit that limit. I chose 200 because it was a nice round number, but definitely need to be above 120. 8k doesn't get me 120, so 16k is next. (Linux doesn't offer a 32k block size?? : </code> http://luhartma.blogspot.com/2006/01/oracle-block-size-specails.html <code>

I do want to ask this one last time. I will try to be as clear as I can.

Can you show me an example of this situation where you *JUST* break the threshhold in 9i. In other words, can you set up one situation where the query executes, and you add a single character to the query (or the output), and that causes it to break. Because to me, it is still very unclear what exactly is overflowing the block within Oracle's guts.

Thanks very much for your continued responses.

Tom Kyte
May 31, 2006 - 10:25 am UTC

It would be a funtion of the size of the columns. It is not really documented. It would be empirical testing to discover it in your precise release.

I'll re-iterate: can we USE A COLLECTION (which can be of rather "large" size)

I don't think so

A reader, May 31, 2006 - 1:39 pm UTC

This operation must be performed in a single sql query. I am not allowed to use any PL/SQL (long story, but client requirement...) Does that kill the collection possibility?

The story is this:
I have a developer pass me a string from our java application like this:

11,1 11,1 11,1 11,1 11,2 11,2 11,2 11,2 23,1 23,1 23,1 23,1 23,1 23,1 45,1 45,1 61,1 84,2 84,2 84,2 84,2 84,2 84,2 84,2 84,2 134,4 134,4 134,4 134,4 134,5 134,5 134,5 134,5

These number||','||number||' ' pairs represent rows in the statecheckcontainer table. Because I am passed this array, I likewise have to change these statecheckcontainer rows into columns for every statecheck on a stateprescription in order to find if a duplicate string exists. If we don't find a duplicate, we create a new prescription, if we find one that exists, my query would return the stateprescriptionid.

Here is the query that works:

select stateprescriptionid
from
(select stateprescriptionid
, trim(max(decode(nvl(rn,0),1, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),2, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),3, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),4, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),5, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),6, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),7, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),8, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),9, containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),10,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),11,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),12,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),13,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),14,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),15,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),16,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),17,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),18,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),19,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),20,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),21,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),22,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),23,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),24,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),25,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),26,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),27,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),28,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),29,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),30,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),31,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),32,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),33,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),34,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),35,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),36,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),37,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),38,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),39,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),40,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),41,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),42,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),43,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),44,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),45,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),46,containerid||','||containerquantity||' ',nvl(rn,0),null,null)) ||
max(decode(nvl(rn,0),200,containerid||','||containerquantity||' ',nvl(rn,0),null,null))) containerids_quantities
from (select t3.stateprescriptionid
, t1.containerid
, t1.containerquantity
, row_number () over (partition by t3.stateprescriptionid
order by t1.containerid, t1.containerquantity
) rn
from statecheckcontainer t1 join statecheck t2 on t1.statecheckid = t2.statecheckid
join stateprescription t3 on t2.stateprescriptionid = t3.stateprescriptionid
)
group by stateprescriptionid
)
where containerids_quantities = '11,1 11,1 11,1 11,1 11,2 11,2 11,2 11,2 23,1 23,1 23,1 23,1 23,1 23,1 45,1 45,1 61,1 84,2 84,2 84,2 84,2 84,2 84,2 84,2 84,2 134,4 134,4 134,4 134,4 134,5 134,5 134,5 134,5'
;

Can collections duplicate this?


Tom Kyte
May 31, 2006 - 3:34 pm UTC

how the heck can a "customer requirement" come into play here.

Customers don't tell us how to write code, they tell us "I need to do this, make it so"


So, you don't even NEED this string!!!! arg...

What we really want to do is so simple, so so silly simple.

You obviously want to use "in" and count. We don't need to do any of this at all.


select stateprescriptionid
from (select t3.stateprescriptionid
, t1.containerid
, t1.containerquantity
from statecheckcontainer t1 join statecheck t2 on t1.statecheckid = t2.statecheckid join
stateprescription t3 on t2.stateprescriptionid = t3.stateprescriptionid
where (containerid,containerquantity) in (that set)
)
group by stateprescriptionid
having count(*) = (cardinality of that set)
);


is the query you are really after, isn't it.

Let's follow this a bit - tell us more about this data. You have 11,1 repeated for example - is that "relevant" or are the items really distinct in this set.


A reader, May 31, 2006 - 4:03 pm UTC

I am here to tell you, no PL/SQL. Period.

I am bound by that.

The duplication of those containerids and quantities is relevant.

I don't think that query will work because it's the entire string put together as a unique combination that must be evaluated in full. Not pieces of it.

Here is what I should have provided you with initially.

Sorry for that.

CREATE TABLE StatePrescription
(StatePrescriptionId NUMBER NOT NULL,
LastUpdateStaffMemberId NUMBER,
LastUpdateProgramName VARCHAR2(30),
LastUpdateDateTime DATE)
;

CREATE TABLE StateCheck
(StateCheckId NUMBER NOT NULL,
StatePrescriptionId NUMBER,
LastUpdateStaffMemberId NUMBER,
LastUpdateProgramName VARCHAR2(30),
LastUpdateDateTime DATE,
SequenceNumber NUMBER)
;
CREATE TABLE StateCheckContainer
(StateCheckContainerId NUMBER NOT NULL,
StateCheckId NUMBER,
ContainerId NUMBER,
ContainerQuantity NUMBER,
FirstCheckIndicator VARCHAR2(1),
LastCheckIndicator VARCHAR2(1),
ContainerIsolationCode VARCHAR2(10),
LastUpdateStaffMemberId NUMBER,
LastUpdateProgramName VARCHAR2(30),
LastUpdateDateTime DATE)
;

INSERT INTO STATEPRESCRIPTION
(StatePrescriptionId,LastUpdateStaffMemberId,LastUpdateProgramName,LastUpdateDateTime)
VALUES
(10000005,NULL,null,'5/25/2006')
/

INSERT INTO statecheck
VALUES
(10000033,10000005,NULL,NULL,NULL,1)
/
INSERT INTO statecheck
VALUES
(10000034,10000005,NULL,NULL,NULL,2)
/
INSERT INTO statecheck
VALUES
(10000035,10000005,NULL,NULL,NULL,3)
/
INSERT INTO statecheck
VALUES
(10000036,10000005,NULL,NULL,NULL,4)
/
INSERT INTO statecheck
VALUES
(10000037,10000005,NULL,NULL,NULL,5)
/
INSERT INTO statecheck
VALUES
(10000038,10000005,NULL,NULL,NULL,6)
/
INSERT INTO statecheck
VALUES
(10000039,10000005,NULL,NULL,NULL,7)
/
INSERT INTO statecheck
VALUES
(10000040,10000005,NULL,NULL,NULL,8)
/
INSERT INTO statecheckcontainer
VALUES
(10000109,10000033,61,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000110,10000033,45,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000111,10000033,23,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000112,10000033,134,5,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000113,10000033,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000114,10000033,11,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000115,10000034,45,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000116,10000034,23,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000117,10000034,134,5,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000118,10000034,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000119,10000034,11,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000120,10000035,23,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000121,10000035,134,5,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000122,10000035,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000123,10000035,11,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000124,10000036,23,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000125,10000036,134,5,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000126,10000036,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000127,10000036,11,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000128,10000037,23,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000129,10000037,134,4,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000130,10000037,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000131,10000037,11,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000132,10000038,23,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000133,10000038,134,4,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000134,10000038,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000135,10000038,11,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000136,10000039,134,4,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000137,10000039,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000138,10000039,11,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000139,10000040,134,4,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000140,10000040,84,2,NULL,NULL,NULL,10000002,null,'5/25/2006')
/
INSERT INTO statecheckcontainer
VALUES
(10000141,10000040,11,1,NULL,NULL,NULL,10000002,null,'5/25/2006')
/



Tom Kyte
June 01, 2006 - 8:39 am UTC

it is all about sets....

consider if you had this set:

ops$tkyte@ORA9IR2> variable x varchar2(4000)
ops$tkyte@ORA9IR2> exec :x := '11,1 11,1 11,1 11,1 11,2 11,2 11,2 11,2 23,1 23,1 23,1 23,1 23,1 23,1 45,1 45,1 61,1 84,2 84,2 84,2 84,2 84,2 84,2 84,2 84,2 134,4 134,4 134,4 134,4 134,5 134,5 134,5 134,5'

PL/SQL procedure successfully completed.

ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> with data
  2  as
  3  (
  4  select l,
  5         to_number( substr(token,1,instr(token,',')-1) ) id1,
  6             to_number( substr(token,instr(token,',')+1 ) ) id2
  7    from (
  8  select level l,
  9         substr (txt,
 10                 instr (txt, '|', 1, level  ) + 1,
 11                 instr (txt, '|', 1, level+1) - instr (txt, '|', 1, level) -1 )
 12           as token
 13    from (
 14  select '|'||replace(:x,' ','|')||'|' txt
 15    from dual
 16         )
 17  connect by level <= length(txt)-length(replace(txt,'|',''))-1
 18         )
 19  )
 20  select * from data;

         L        ID1        ID2
---------- ---------- ----------
         1         11          1
         2         11          1
         3         11          1
         4         11          1
         5         11          2
         6         11          2
         7         11          2
         8         11          2
         9         23          1
        10         23          1
        11         23          1
        12         23          1
        13         23          1
        14         23          1
        15         45          1
        16         45          1
        17         61          1
        18         84          2
        19         84          2
        20         84          2
        21         84          2
        22         84          2
        23         84          2
        24         84          2
        25         84          2
        26        134          4
        27        134          4
        28        134          4
        29        134          4
        30        134          5
        31        134          5
        32        134          5
        33        134          5

33 rows selected.


Which we obviously do.  It is orderable (L) - it is full of numbers (convenient, that is your datatype too!).  We can select from it like a table (because it in fact is a table...).  We can use it in an "in", we can join to it....

The possibilities :)

Try this query, I believe it to be correct - I've commented inline a bit the logic:


ops$tkyte@ORA9IR2> with data
  2  as
  3  (
  4  select l,
  5         to_number( substr(token,1,instr(token,',')-1) ) containerid,
  6             to_number( substr(token,instr(token,',')+1 ) ) containerquantity
  7    from (
  8  select level l,
  9         substr (txt,
 10              instr (txt, '|', 1, level  ) + 1,
 11              instr (txt, '|', 1, level+1) - instr (txt, '|', 1, level) -1 )
 12           as token
 13    from (
 14  select '|'||replace(:x,' ','|')||'|' txt
 15    from dual
 16         )
 17  connect by level <= length(txt)-length(replace(txt,'|',''))-1
 18         )
 19  ),

<b>Our important set of containerids/containerquantities to find, ordered by L</b>

 20  possibles
 21  as
 22  (select *
 23     from (select  t3.stateprescriptionid
 24              , t1.containerid
 25              , t1.containerquantity
 26              , row_number ()
 27                 over (partition by t3.stateprescriptionid
 28                       order by t1.containerid, t1.containerquantity
 29                      ) rn,
 30                count(*)
 31                  over (partition by t3.stateprescriptionid
 32                       ) cnt
 33        from (select *
 34                from statecheckcontainer
 35               where statecheckid in
 36                  (select statecheckid
 37                     from statecheckcontainer
 38                    where (containerid,containerquantity) in
 39                          (select containerid, containerquantity
 40                             from data)
 41                  )
 42             ) t1 join
 43             statecheck t2
 44                on t1.statecheckid = t2.statecheckid join
 45             stateprescription t3
 46                on t2.stateprescriptionid = t3.stateprescriptionid
 47       )
 48   where cnt = (select count(*) from data)
 49  ),


<b>these are the only stateprescriptionid values we need to consider.  And notice that we may be able to use a nice index on T1 if it would be deemed useful.

We use row_number() to be able to sequence them just like you did, and we use count(*) over to figure out how many we found for each.  We only really keep the truly possible possibles now (where cnt=....). 

NOTE: care was taken with T1 there - to get all of the needed rows to be considered, we are getting the same set of rows you were ultimately comparing.

Be very nice to perhaps have index on t1(containerid,containerquantity,statecheckid) and t1(statecheckid) perhaps - to find these rows rapidly (assuming this is selective enough of course) </b>

 50  jointo
 51  as
 52  (select data.l, data.containerid,
 53          data.containerquantity, possibles.stateprescriptionid
 54     from data,
 55          (select distinct stateprescriptionid
 56             from possibles) possibles
 57  )


<b>Jointo is needed in 9i - but won't be in 10g (with a PARTITIONED OUTER JOIN).  What we need is the set of all possible stateprescriptionid's and "datas" - we need to join data to each "set of stateprescriptionid's in possibles" - cartesian join does that for us</b>

 58  select p.stateprescriptionid
 59    from possibles p, jointo j
 60   where p.stateprescriptionid = j.stateprescriptionid
 61     and p.containerid = j.containerid
 62     and p.containerquantity = j.containerquantity
 63     and p.rn = j.l
 64   group by p.stateprescriptionid
 65  having count(*) = (select count(*) from data)
 66  /

STATEPRESCRIPTIONID
-------------------
           10000005

<b>then we just join possibles to jointo by the full key - count up the resulting joined rows by statprescriptionid - and only keep those that have the same count as the rows in data (eg: we found ALL of the rows)</b> 

A reader, June 01, 2006 - 10:59 am UTC

I'm totally blown away by that query.
Give me some time to digest it.



Ugh...

A reader, June 01, 2006 - 3:07 pm UTC

having count(*) = (select count(*) from data)
*
ERROR at line 65:
ORA-00600: internal error code, arguments: [kkqwrm_noref: COLFDNF set], [], [], [], [], [], [], []

Any ideas what might cause that?

I'll check metalink.

Thanks


9.2.0.4 appears to have an issue... 9.2.0.6 works

A reader, June 01, 2006 - 3:45 pm UTC

I found a note (Doc ID: Note:361234.1) that said set query_rewrite_enabled = true. I set it in my session and tried again, but received the same error.

I tried the query in 9.2.0.6 and it works perfectly, and in micro-seconds on the full set of data. Not to mention even faster than the other analytic query I was trying to construct.

There is no proper or sufficiently meaningful way to say thank you for how you positively impact people (with an occasional smidgen of harassment LOL). That query uses concepts I've not employed in my work as a DBA yet, and it stretches my understanding of Oracle.

T h a n k Y o u




Tom Kyte
June 01, 2006 - 4:17 pm UTC

Another workaround for 9204 should be to not use the ANSI JOIN in the inline view - use the "old fashioned" way.

Like I did on lines 58 on...

Looks like it was corrected in 9205 (with a backport for 9204, hence 9205 on up should have it corrected)

Sounds good

A reader, June 02, 2006 - 7:29 am UTC

I'll try it.

I couldn't get that to work in 9.2.0.4.

A reader, June 02, 2006 - 1:16 pm UTC

What's your stance on upgrading?

You think we should just go to 9.2.0.7?

Thanks

Tom Kyte
June 02, 2006 - 3:03 pm UTC

I will have to recommend using 9207 - yes.

But we could do this as a "two step" in 9204 with global temporary tables.

How to calculate Length of sort key

Manoj Pradhan, May 05, 2007 - 10:03 am UTC

Tom ,
1. If I am not wrong the lenth of sort key , the Query you have given in the first follow up this artickle .

Assuming all columns contians full data ie 4000 byte .
select x , y , z , sum (a)
from t
group by x , y ,z

Then Sort key length is :-

4000 + 4000 + 4000 + 22 = 12022 bytes . ( maximum possible value )

2. Whether Sort key length depend upon only columns present in select clause ?

3 . consider your table t have another columns
I integer ,
J integer ,
M varchar2(4000) ,
N varchar2(4000) ,

and all contains full data , ( I = 1 , J = 2 ) .

select x, y, z, max(a) , max( decode ( i ,1 , M )) ,
max( decode ( j , 2 , N ) )
from t
group by x , y, x

what will be the maximum possible length of sort key .
and How it calculated .

Please explian .







Tom Kyte
May 08, 2007 - 10:15 am UTC

the sort key will be a function of the selected columns length, yes.

Manoj Pradhan, May 10, 2007 - 10:55 am UTC

Tom,
Please provide me some links where I can get more information about Sort Key Error , and what are the approaches to solve it .

In 11g this error is solved ?

Ramakrishnan, May 05, 2009 - 4:58 am UTC

Hi Tom,

 I am not getting this error in 11g, but my customer reported this error in 10g.
Is this problems is solved in 11g. 

SQL*Plus: Release 11.1.0.7.0 - Production on Tue May 5 13:42:46 2009

Copyright (c) 1982, 2008, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> desc t;
 Name           Null?    Type
 -----------------------------------------
 X  VARCHAR2(4000)
 Y  VARCHAR2(4000)
 Z  VARCHAR2(4000)
 A  NUMBER(38)

SQL> select count(*) from t;


  COUNT(*)
----------
    290152

select x, y, z, sum(a)    from t      group by x, y, z;

........
.........

    SUM(A)
----------
    580304

SQL> show parameter  db_block_size

NAME                  TYPE        VALUE
------------------------------------ ----------- 
db_block_size         integer     8192


Best regards 
Ramakrishnan.A 

Tom Kyte
May 11, 2009 - 8:27 am UTC

It isn't really useful to see information about a system where it works.

This is a function of the blocksize. Your blocksize is 8k, my blocksize is 8k. In 10g, I have no issues with this.


so, we must presume your customer has a "small blocksize"

ops$tkyte%ORA10GR2> create table t
  2  as
  3  select rpad(rownum,4000,rownum) x,
  4         rpad(rownum,4000,rownum) y,
  5         rpad(rownum,4000,rownum) z,
  6             rownum a
  7    from dual connect by level <= 10000
  8  /

Table created.

ops$tkyte%ORA10GR2> set autotrace traceonly
ops$tkyte%ORA10GR2> select x, y, z, sum(a) from t group by x,y,z;

9892 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 47235625

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      | 11478 |    65M|  1168   (2)| 00:00:09 |
|   1 |  HASH GROUP BY     |      | 11478 |    65M|  1168   (2)| 00:00:09 |
|   2 |   TABLE ACCESS FULL| T    | 11478 |    65M|  1167   (1)| 00:00:09 |
---------------------------------------------------------------------------

Note
-----
   - dynamic sampling used for this statement


Statistics
----------------------------------------------------------
        198  recursive calls
          0  db block gets
      33323  consistent gets
      27806  physical reads
          0  redo size
  119373847  bytes sent via SQL*Net to client
       7649  bytes received via SQL*Net from client
        661  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       9892  rows processed

ops$tkyte%ORA10GR2> set autotrace off

So we have a bug there

adderek, June 14, 2010 - 6:38 am UTC

Hi,
This makes Oracle way less flexible, especially for data mining apps. I personally would classify this as a painful functional constraint that should be removed/fixed.
There is a max of 1000 columns in Oracle.
There is a limitation for queries to fit into 1 db block when using features as already described.
Anything more we should know about?
Regards
Tom Kyte
June 22, 2010 - 8:36 am UTC

did you read the page? this was addressed many many many years ago.


ops$tkyte%ORA10GR2> drop table t;

Table dropped.

ops$tkyte%ORA10GR2> variable x refcursor
ops$tkyte%ORA10GR2> declare
  2          l_query long := 'create table t ( c1 char(2000) ';
  3  begin
  4          for i in 2 .. 100
  5          loop
  6                  l_query := l_query || ', c' || i || ' char(2000) default rpad(''x'',2000,''x'') ';
  7          end loop;
  8          l_query := l_query || ')';
  9          execute immediate l_query;
 10
 11          for i in 1..5
 12          loop
 13                  execute immediate 'insert into t (c1) values ( to_char(:x) )' using i;
 14          end loop;
 15          commit;
 16
 17          l_query := 'select count(*) ';
 18          for i in 1 .. 100
 19          loop
 20                  l_query := l_query || ', c' || i;
 21          end loop;
 22          l_query := l_query || ' from t group by c1';
 23          for i in 2 .. 100
 24          loop
 25                  l_query := l_query || ', c' || i;
 26          end loop;
 27          open :x for l_query;
 28  end;
 29  /

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> print x

  COUNT(*)
----------
C1
----------------------------------------------------------------------------------------------------
C2
----------------------------------------------------------------------------------------------------
C3
----------------------------------------------------------------------------------------------------
C4
....
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


ops$tkyte%ORA10GR2> spool off

Strange issue

adderek, June 15, 2010 - 7:40 am UTC

Hi,
Lately we have observed a strange issue when dealing with a large aggregation query. It contained many SUM statements and not much more. This caused "sort key too long" problem. However adding a dummy AVG(anything) column to the query fixed the issue. A bug?
Regards
Tom Kyte
June 22, 2010 - 10:19 am UTC

need example

sort key too long

Prakash, October 12, 2011 - 11:21 am UTC

This is rather question than a review. Honestly the whole discussion is helpful.

I have a query over 100 varchar2(4000) columns in SELECT and GROUP BY, which obviously failed in 9.2 but runs great on 11g Exadata.

What's the 11g + Exadata does differently that 9i 64bit. Both environments have 8K block size.
Tom Kyte
October 12, 2011 - 12:05 pm UTC

things change over time - most of the sort key limitations have been removed starting in 10g ...


ops$tkyte%ORA9IR2> create table t ( a char(2000), b char(2000), c char(2000), d char(2000), e char(2000), f char(2000) );

Table created.

ops$tkyte%ORA9IR2> insert into t values ( 1, 2, 3, 4, 5, 6 );

1 row created.

ops$tkyte%ORA9IR2> commit;

Commit complete.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> select count(*) from t group by a,b,c,d,e,f order by a,b,c,d,e,f;
select count(*) from t group by a,b,c,d,e,f order by a,b,c,d,e,f
                     *
ERROR at line 1:
ORA-01467: sort key too long


----------------------------------------------------------
ops$tkyte%ORA10GR2> create table t ( a char(2000), b char(2000), c char(2000), d char(2000), e char(2000), f char(2000) );

Table created.

ops$tkyte%ORA10GR2> insert into t values ( 1, 2, 3, 4, 5, 6 );

1 row created.

ops$tkyte%ORA10GR2> commit;

Commit complete.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> select count(*) from t group by a,b,c,d,e,f order by a,b,c,d,e,f;

  COUNT(*)
----------
         1