Oracle FAQ | Your Portal to the Oracle Knowledge Grid |
Home -> Community -> Mailing Lists -> Oracle-L -> RE: Buffer Sort explanation
Here's a test I did to try and understand this BUFFER SORT behavior. In the end, I noticed differences in when the optimizer chose to use a BUFFER SORT operation primarily when it was operating under an IO cost model and when the filter condition in the predicate was against a column that did not have an index and when the filter condition cardinality was estimated at 1 row.
The behavior evidenced by the IO cost model is what I saw consistently in Oracle v9 but in v10, I'm not seeing the BUFFER SORT operations chosen as frequently. This may be an example of the fine-tuning of the algorithms Lex mentioned.
This example is a bit long, but it illustrates the behavior and seems to indicate that revisits to PGA (under certain circumstances) appears to be favored over shared memory accesses.
Karen Morton
Hotsos Enterprises, Ltd.
http://www.hotsos.com
Upcoming events at http://www.hotsos.com/education/schedule.html
SQL> @hparam _optimizer_cost_model
More:
Parameter Name Parameter Value _optimizer_cost_model CHOOSE
1 row selected.
SQL>
SQL> get test1
1 select c.class_desc, c.credit_hrs, s.student_name, avg(g.grade_received) grade_avg
2 from class c, student1 s, grades g
3 where g.student_id = s.student_id 4 and c.class_desc = 'English 101' 5 and c.class_id = g.class_id 6 group by cube (c.class_desc, c.credit_hrs, s.student_name)7 having grouping(c.class_desc) = 0
SQL> @hix class
Index Flags Height Column Name ------------------------------ ------- ------ ------------------------------ CLASS_ID_PK U 1 CLASS_IDSQL>
SQL> @hxplan
Enter .sql file name (without extension) []: test1
Enter the display level (TYPICAL, ALL, BASIC, SERIAL) [TYPICAL] :
|* 1 | FILTER | | | | | |
| 2 | SORT GROUP BY ROLLUP | | 3 | 138 | 8 (25)| 00:00:01 |
|* 3 | HASH JOIN | | 12 | 552 | 7 (15)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| GRADES | 12 | 108 | 2 (0)| 00:00:01 |
| 5 | NESTED LOOPS | | 12 | 360 | 4 (0)| 00:00:01 |
|* 6 | TABLE ACCESS FULL | CLASS | 1 | 21 | 2 (0)| 00:00:01 | |* 7 | INDEX RANGE SCAN | GRADES_PK | 12 | | 1 (0)| 00:00:01 |
| 8 | TABLE ACCESS FULL | STUDENT1 | 18 | 288 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
1 - filter(GROUPING("C"."CLASS_DESC")=0 AND GROUPING("C"."CREDIT_HRS")=0) 3 - access("G"."STUDENT_ID"="S"."STUDENT_ID") 6 - filter("C"."CLASS_DESC"='English 101') 7 - access("C"."CLASS_ID"="G"."CLASS_ID")SQL>
SQL> get test2
1 select c.class_desc, c.credit_hrs, s.student_name, avg(g.grade_received) grade_avg
2 from class c, student1 s, grades g
3 where g.student_id = s.student_id 4 and c.class_id = 2 5 and c.class_id = g.class_id 6 group by cube (c.class_desc, c.credit_hrs, s.student_name)7 having grouping(c.class_desc) = 0
SQL> @hxplan
Enter .sql file name (without extension) [TEST1]: test2
Enter the display level (TYPICAL, ALL, BASIC, SERIAL) [TYPICAL] :
|* 1 | FILTER | | | | | |
| 2 | SORT GROUP BY ROLLUP | | 3 | 138 | 7 (29)| 00:00:01 |
|* 3 | HASH JOIN | | 12 | 552 | 6 (17)| 00:00:01 |
| 4 | NESTED LOOPS | | 12 | 360 | 3 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| CLASS | 1 | 21 | 1 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | CLASS_ID_PK | 1 | | 0 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| GRADES | 12 | 108 | 2 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | GRADES_PK | 12 | | 1 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | STUDENT1 | 18 | 288 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
1 - filter(GROUPING("C"."CLASS_DESC")=0 AND GROUPING("C"."CREDIT_HRS")=0) 3 - access("G"."STUDENT_ID"="S"."STUDENT_ID") 6 - access("C"."CLASS_ID"=2) 8 - access("G"."CLASS_ID"=2)
SQL> alter session set "_optimizer_cost_model" = io ;
Session altered.
SQL> @hparam _optimizer_cost_model
More:
Parameter Name Parameter Value _optimizer_cost_model IO
1 row selected.
SQL>
SQL> get test1
1 select c.class_desc, c.credit_hrs, s.student_name, avg(g.grade_received) grade_avg
2 from class c, student1 s, grades g
3 where g.student_id = s.student_id 4 and c.class_desc = 'English 101' 5 and c.class_id = g.class_id 6 group by cube (c.class_desc, c.credit_hrs, s.student_name)7 having grouping(c.class_desc) = 0
SQL> @hxplan
Enter .sql file name (without extension) [TEST2]: test1
Enter the display level (TYPICAL, ALL, BASIC, SERIAL) [TYPICAL] :
|* 1 | FILTER | | | | |
| 2 | SORT GROUP BY ROLLUP | | 3 | 138 | 9 |
|* 3 | HASH JOIN | | 12 | 552 | 7 |
| 4 | MERGE JOIN CARTESIAN| | 18 | 666 | 4 |
|* 5 | TABLE ACCESS FULL | CLASS | 1 | 21 | 2 |
| 6 | BUFFER SORT | | 18 | 288 | 2 |
| 7 | TABLE ACCESS FULL | STUDENT1 | 18 | 288 | 2 |
| 8 | TABLE ACCESS FULL | GRADES | 119 | 1071 | 2 |
--------------------------------------------------------------------
Predicate Information (identified by operation id):
1 - filter(GROUPING("C"."CLASS_DESC")=0 AND
GROUPING("C"."CREDIT_HRS")=0)
3 - access("G"."STUDENT_ID"="S"."STUDENT_ID" AND "C"."CLASS_ID"="G"."CLASS_ID") 5 - filter("C"."CLASS_DESC"='English 101')
Note
SQL> get test2
1 select c.class_desc, c.credit_hrs, s.student_name, avg(g.grade_received) grade_avg
2 from class c, student1 s, grades g
3 where g.student_id = s.student_id 4 and c.class_id = 2 5 and c.class_id = g.class_id 6 group by cube (c.class_desc, c.credit_hrs, s.student_name)7 having grouping(c.class_desc) = 0
|* 1 | FILTER | | | | |
| 2 | SORT GROUP BY ROLLUP | | 3 | 138 | 8 |
|* 3 | HASH JOIN | | 12 | 552 | 6 |
| 4 | NESTED LOOPS | | 12 | 360 | 3 |
| 5 | TABLE ACCESS BY INDEX ROWID| CLASS | 1 | 21 | 1 |
|* 6 | INDEX UNIQUE SCAN | CLASS_ID_PK | 1 | | |
| 7 | TABLE ACCESS BY INDEX ROWID| GRADES | 12 | 108 | 2 |
|* 8 | INDEX RANGE SCAN | GRADES_PK | 12 | | 1 |
| 9 | TABLE ACCESS FULL | STUDENT1 | 18 | 288 | 2 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
1 - filter(GROUPING("C"."CLASS_DESC")=0 AND
GROUPING("C"."CREDIT_HRS")=0)
3 - access("G"."STUDENT_ID"="S"."STUDENT_ID") 6 - access("C"."CLASS_ID"=2) 8 - access("G"."CLASS_ID"=2)
Note
Session altered.
-----Original Message-----
From: Lex de Haan [mailto:lex.de.haan_at_naturaljoin.nl]
Sent: Sunday, August 07, 2005 11:07 AM
To: lambu999_at_gmail.com
Cc: 'oracle-l'
Subject: RE: Buffer Sort explanation
that's indeed how I understand it. obviously, there must be some cut off number or threshold value -- and obviously, it is highly undocumented; I don't have a clue :-)
by the way, even if I would have a clue, these algorithms are typically fine-tuned by Oracle development with every release, without letting us know...
kind regards,
Lex.
-----Original Message-----
Hi Lex,
If Oracle determines that if a block will be accessed multiple times by the _same_ SQL, then it moves it to PGA. If the same can be accessed multiple times by _different_ SQL statements it ends up in SGA? Is there a cut off number for accessing the data block above which Oracle places it to PGA?
On 8/4/05, Lex de Haan <lex.de.haan_at_naturaljoin.nl> wrote:
> a BUFFER SORT typically means that Oracle reads data blocks into > private memory, because the block will be accessed multiple times in > the context of the SQL statement execution. in other words, Oracle > sacrifies some extra memory to reduce the overhead of accessing blocks > multiple times in shared memory. this has nothing to do with sorting ...
-- http://www.freelists.org/webpage/oracle-lReceived on Sun Aug 07 2005 - 14:54:14 CDT