2

テスト テーブルを作成します。

create table customer (first_name varchar2(20), last_name varchar2(20) not null, address varchar(20));

insert into customer select dbms_random.string('U', 20), dbms_random.string('U', 20), dbms_random.string('U', 20) from dual connect by level <= 100000;
commit;

create index i_ln_fn_0 on customer(last_name, first_name,0); — just to be sure that all rows are indexed

今説明計画:

explain plan for
select /*+ FIRST_ROWS(20) */ *
  from CUSTOMER
  where first_name like 'AB%'
    and first_name is not null
  order by last_name;

select * from table(dbms_xplan.display);

-------------------------------------------------------------------------------
| Id  | Operation          | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |          |   197 | 12411 |   275   (2)| 00:00:04 |
|   1 |  SORT ORDER BY     |          |   197 | 12411 |   275   (2)| 00:00:04 |
|*  2 |   TABLE ACCESS FULL| CUSTOMER |   197 | 12411 |   274   (1)| 00:00:04 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("FIRST_NAME" LIKE 'AB%' AND "FIRST_NAME" IS NOT NULL)

しかし、最初の行だけが必要なので、テーブル全体の並べ替えは避けたいと思います。次のような計画を立てたいと思います。

SELECT STATEMENT
    TABLE ACCESS BY ROWID (customer)
        INDEX FULL SCAN (i_ln_fn_0)

ソートを回避するようにデータベースを説得する方法は?

問題はさらに深刻です。どこでも last_name のみを使用する場合でも:

explain plan for
select /*+ FIRST_ROWS(20) */ last_name
  from CUSTOMER
  where last_name like 'AB%'
    and last_name is not null
  order by last_name;

select * from table(dbms_xplan.display);

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |    17 |   357 |     4  (25)| 00:00:01 |
|   1 |  SORT ORDER BY    |           |    17 |   357 |     4  (25)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN| I_LN_FN_0 |    17 |   357 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("LAST_NAME" LIKE 'AB%')
       filter("LAST_NAME" LIKE 'AB%')

ここでは、並べ替えは実​​際には必要ありませんが、データベースはまだそれを使用しています。なんで?

編集:両方でテスト済み

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
"CORE 11.2.0.1.0 Production"
TNS for 64-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production+
PL/SQL Release 11.2.0.2.0 - Production+
"CORE 11.2.0.2.0Production"+
TNS for IBM/AIX RISC System/6000: Version 11.2.0.2.0 - Production+
NLSRTL Version 11.2.0.2.0 - Production+

同じプランで。

4

1 に答える 1

2

理由は、NLS_SORT パラメータの値が間違っていたことです。それをBINARYに変更した後、計画は私が望んでいたように見え始めました.

http://docs.oracle.com/cd/E24693_01/server.11203/e24448/initparams152.htmから:

NLS_SORT の値は、クエリの実行計画に影響します。標準インデックスは言語順に並べ替えられた値のソースとして使用できないため、通常、インデックス範囲スキャンの代わりに明示的な並べ替え操作を実行する必要があります。NLSSORT 関数の関数インデックスを定義して、言語順に並べ替えられた値を提供し、実行計画にインデックス範囲スキャンを再導入することができます。

(forums.oracle com の Paul Horth からこの回答を得ました。)

于 2013-03-07T11:23:33.657 に答える