About
FIRST_ROWS is an optimizer goal in order to ask it the best response time.
You can instruct this instruction through:
- a hint
- or by setting the value of the optimizer goal
In the two case, it instructs Oracle to optimize an individual SQL statement with a goal of best response time to return the first rows.
This hint uses a cost-based approach for the SQL statement, regardless of the presence of statistic.
Articles Related
Example
With FIRST_ROWS
For example, suppose that your interactive application runs a query that returns 50 rows. This application initially fetches only the first 25 rows of the query to present to the end user. You want the optimizer to generate a plan that gets the first 25 records as quickly as possible so that the user is not forced to wait. You can use a hint to pass this instruction to the optimizer as shown below
SELECT /*+ FIRST_ROWS(25) */ employee_id, department_id
FROM hr.employees
WHERE department_id > 50;
------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 26 | 182
| 1 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 26 | 182
|* 2 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | |
------------------------------------------------------------------------
This execution plan shows that the optimizer chooses an index on the employees.department_id column to find the first 25 rows of employees whose department ID is over 50. The optimizer uses the rowid retrieved from the index to retrieve the record from the employees table and return it to the client. Retrieval of the first record is typically almost instantaneous.
Without FIRST_ROWS
The SQL statement shows the same statement, but without the optimizer hint.
SELECT employee_id, department_id
FROM hr.employees
WHERE department_id > 50;
------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cos
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 50 | 350 |
|* 1 | VIEW | index$_join$_001 | 50 | 350 |
|* 2 | HASH JOIN | | | |
|* 3 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 50 | 350 |
| 4 | INDEX FAST FULL SCAN| EMP_EMP_ID_PK | 50 | 350 |
This execution plan joins two indexes to return the requested records as fast as possible. Rather than repeatedly going from index to table as with the FIRST_ROWS hint, the optimizer chooses a range scan of EMP_DEPARTMENT_IX to find all rows where the department ID is over 50 and place these rows in a hash table. The optimizer then chooses to read the EMP_EMP_ID_PK index. For each row in this index, it probes the hash table to find the department ID.
In this case, the database cannot return the first row to the client until the index range scan of EMP_DEPARTMENT_IX completes. Thus, this generated plan would take longer to return the first record. Unlike the previous plan, which accesses the table by index rowid, the plan in this example uses multiblock I/O, resulting in large reads. The reads enable the last row of the entire result set to be returned more rapidly.