1

以下は、集計関数を使用しているクエリです。where 句は単純で、 corpId と incoming_date にインデックスがあります。単純にすべての行を取得/カウントすると、クエリにかかる時間は 1 秒未満になります。ただし、集計関数を使用すると、クエリに約 4 分かかります。Oracle 11i を使用しており、where 句が取得する合計行数は約 64000 です。テーブルとインデックスの統計も最近収集され、テーブルに新しい行は追加されていません。

速度の改善について提案してください。

SELECT
sum(paid_amt) totalamount
FROM test_table e
WHERE  e.corpId =6
AND e. incoming_date >= to_date('01-12-2012','dd-mm-yyyy')
AND e. incoming _date <= to_date('09-01-2013','dd-mm-yyyy')
4

2 に答える 2

3

paid_amtインデックスに含める:

CREATE INDEX
        ix_testtable_cord_date_paid
ON      test_table (corpId, incoming_date, paid_amt)

just にインデックスがあり、次の(corpId, incoming_date)ように速度をテストしようとする場合:

SELECT  COUNT(*)
FROM    test_table
WHERE   e.corpId = 6
        AND e.incoming_date >= to_date('01-12-2012','dd-mm-yyyy')
        AND e.incoming_date <= to_date('09-01-2013','dd-mm-yyyy')

インデックス以外のクエリを実行しないため、クエリはINDEX (RANGE SCAN)単独で満足できます。

インデックスにないものを追加するとすぐに(paid_amtあなたの場合)、クエリは追加を使用TABLE ACCESS (BY INDEX ROWID)してテーブルからレコードを取得する必要があります。

これは入れ子になったループでのランダム ルックアップであり、特にテーブル レコードが大きい場合 (多くのフィールドまたは長いフィールドがある場合) は遅くなります。

オプティマイザは、このアクセス方法が より効率的ではないと判断し、FULL SCAN代わりに後者を使用することさえあります。

于 2013-04-16T10:30:07.717 に答える
0

このシナリオをこのように再現しました...

CREATE TABLE test_table 
  ( id integer
  , corpId integer
  , paid_amt number(10,2)
  , incoming_date DATE );

ALTER TABLE test_table
add CONSTRAINT test_table_pk PRIMARY KEY (id);

create index test_table_nui_1 on test_table(corpId);

create index test_table_nui_2 on test_table(incoming_date);

create sequence test_table_seq;

insert into test_table
  select test_table_seq.nextval
       ,MOD(test_table_seq.currval,6)
       ,MOD(test_table_seq.currval,10) + 1
       ,sysdate - MOD(test_table_seq.currval,200) 
  from all_objects, user_objects;  

all_objects と user_objects の間のデカルト結合は、大量のレコードをすばやく挿入するための単なるハックです。(この場合は 657,000 行)

最初にすべての 657,000 を選択して実行します...

select sum(paid_amt)
from test_table;

Plan SELECT STATEMENT ALL_ROWSCost: 621 Bytes: 13 Cardinality: 1
2 SORT AGGREGATE Bytes: 13 Cardinality: 1
1 TABLE ACCESS FULL TABLE DAVE.TEST_TABLE Cost: 621 Bytes: 9,923,914 Cardinality: 763,378

次に、1 つの corpId に対して 109,650...

select sum(paid_amt)
from test_table
where corpId = 5;

プラン SELECT ステートメント ALL_ROWSCost: 265 バイト: 26 カーディナリティ: 1
3 SORT AGGREGATE バイト: 26 カーディナリティ: 1 2 TABLE ACCESS BY INDEX ROWID TABLE DAVE.TEST_TABLE
コスト: 265 バイト: 3,310,138 カーディナリティ: 127,313
213 カーディナリティ: 3,054

そして最後に、日付で制限する20,836行...

SELECT sum(paid_amt) totalamount
FROM test_table e
WHERE  e.corpId = 5
AND e. incoming_date >= to_date('01-12-2012','dd-mm-yyyy')
AND e. incoming_date <= to_date('09-01-2013','dd-mm-yyyy')

Plan SELECT STATEMENT ALL_ROWSCost: 265 Bytes: 35 Cardinality: 1
3 SORT AGGREGATE Bytes: 35 Cardinality: 1
2 TABLE ACCESS BY INDEX ROWID TABLE DAVE.TEST_TABLE Cost: 265 Bytes: 871,360 Cardinality: 24,896
1 INDEX RANGE SCAN INDEX DAVE.TEST_NUI_1 213 カーディナリティ: 3,054

3 つのクエリはすべて高速でした (0.5 秒未満)。

別の方法は、nui_1 と nui_2 を削除して、両方の列に結合インデックスを作成することです。これは、私のデータベースで31ミリ秒で実行されました

create index test_table_nui_3 on test_table(corpId, incoming_date);

Plan SELECT STATEMENT ALL_ROWSCost: 15 Bytes: 35 Cardinality: 1
3 SORT AGGREGATE Bytes: 35 Cardinality: 1
2 TABLE ACCESS BY INDEX ROWID TABLE DAVE.TEST_TABLE Cost: 15 Bytes: 871,360 Cardinality: 24,896
1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE_NUI_3 Cost: 3 カーディナリティ: 14

これは、集計関数が問題ではないことを示唆していますが、インデックス作成が問題である可能性があります。最善の方法は、説明計画を確認することです。

于 2013-04-16T12:22:50.883 に答える