1

列「id」として主キーを持つテーブルを考えてみましょう

idの範囲を[1、2、3、4...]として照会する必要があります。

2つのオプションがあります-

1)

Select * from Table where id = 1;
Select * from Table where id = 2;
Select * from Table where id = 3;
Select * from Table where id = 4;

2)

Select * from Table where id in ( 1, 2, 3, 4 );

OracleのDatabseとしてのパフォーマンスと、永続性のためのSpringJDBCTemplateの使用のパフォーマンスが優れているのはどちらですか。データセット1、2、3、4がJavaデータ構造の制限内にあると想定して、アプリケーションの観点からメモリの制約を脇に置きます。

データベース接続プールを使用します。

4

5 に答える 5

5

2番目のクエリは、データベースに1回しかクエリを実行しないため、使用します。それとは別に、データベースに接続するのは1回だけです。

データベース接続にはコストがかかることを忘れないでください(多くのリソースを消費します)。

于 2013-03-02T17:35:46.050 に答える
5

JWとa_horse_with_no_nameのステートメントをバックアップするために、ここにテストがあります。すべて同じ接続を使用しているため、ここでは接続(プーリング)の問題は無視されます。

まず、主キーを使用してテーブルを作成し、オプティマイザーの統計を収集します。

SQL> create table mytable
  2  as
  3   select level id
  4        , lpad('*',1000,'*') filler
  5     from dual
  6  connect by level <= 10000
  7  /

Table created.

SQL> alter table mytable add constraint my_pk primary key (id)
  2  /

Table altered.

SQL> exec dbms_stats.gather_table_stats(user,'mytable')

PL/SQL procedure successfully completed.

次に、ウォームアップとしてすべてのステートメントを共有プールに配置し、クエリの出力のほとんどを削減します。

SQL> select * from mytable where id = 1
  2  /

        ID
----------
FILLER
---------------------------------------------------------------------------------------------------------------------------------------
         1
***************************************************************************************************************************************
***************************************************************************************************************************************
***************************************************************************************************************************************
***************************************************************************************************************************************
***************************************************************************************************************************************
***************************************************************************************************************************************
***************************************************************************************************************************************
*******************************************************


1 row selected.

SQL> select * from mytable where id = 2
  2  /

1 row selected.

SQL> select * from mytable where id = 3
  2  /

1 row selected.

SQL> select * from mytable where id = 4
  2  /

1 row selected.

SQL> select * from mytable where id in (1,2,3,4)
  2  /    

4 rows selected.

次に、自動トレース出力を調べて、データベースが実行する必要のある作業を確認します。

SQL> set autotrace traceonly
SQL> select * from mytable where id = 1
  2  /

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3280897506

---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |     1 |  1005 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| MYTABLE |     1 |  1005 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | MY_PK   |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

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

   2 - access("ID"=1)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
       1387  bytes sent via SQL*Net to client
        448  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select * from mytable where id = 2
  2  /

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3280897506

---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |     1 |  1005 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| MYTABLE |     1 |  1005 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | MY_PK   |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

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

   2 - access("ID"=2)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
       1387  bytes sent via SQL*Net to client
        448  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select * from mytable where id = 3
  2  /

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3280897506

---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |     1 |  1005 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| MYTABLE |     1 |  1005 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | MY_PK   |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

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

   2 - access("ID"=3)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
       1387  bytes sent via SQL*Net to client
        448  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select * from mytable where id = 4
  2  /

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3280897506

---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |     1 |  1005 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| MYTABLE |     1 |  1005 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | MY_PK   |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

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

   2 - access("ID"=4)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
       1387  bytes sent via SQL*Net to client
        448  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select * from mytable where id in (1,2,3,4)
  2  /

4 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1637292604

----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     4 |  4020 |     4   (0)| 00:00:01 |
|   1 |  INLIST ITERATOR             |         |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| MYTABLE |     4 |  4020 |     4   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | MY_PK   |     4 |       |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

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

   3 - access("ID"=1 OR "ID"=2 OR "ID"=3 OR "ID"=4)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
       2435  bytes sent via SQL*Net to client
        448  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          4  rows processed

SQL> set autotrace off

4回3回の一貫した取得と8回の一貫した取得。最後に、すべてのステートメントを10,000回実行して、両方のバリアントの時間を計りましょう。

SQL> set timing on
SQL> declare
  2    v_id     number;
  3    v_filler varchar2(1000);
  4  begin
  5    for i in 1 .. 10000
  6    loop
  7      select *
  8        into v_id, v_filler
  9        from mytable
 10       where id = 1
 11      ;
 12      select *
 13        into v_id, v_filler
 14        from mytable
 15       where id = 2
 16      ;
 17      select *
 18        into v_id, v_filler
 19        from mytable
 20       where id = 3
 21      ;
 22      select *
 23        into v_id, v_filler
 24        from mytable
 25       where id = 4
 26      ;
 27    end loop;
 28  end;
 29  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.03
SQL> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.00
SQL> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.99
SQL> declare
  2    v_id     number;
  3    v_filler varchar2(1000);
  4  begin
  5    for i in 1 .. 10000
  6    loop
  7      for r in (select * from mytable where id in (1,2,3,4))
  8      loop
  9        v_id := r.id;
 10        v_filler := r.filler;
 11      end loop;
 12    end loop;
 13  end;
 14  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.41
SQL> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.39
SQL> /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.39
SQL> set timing off

ここでは、データベースに4倍以上のステートメントを送信するオーバーヘッドが最も重要であることがわかります。インデックスの深さとクラスタリング係数に応じて、あちこちでいくつかのバリエーションが可能ですが、1つのクエリと4つのクエリの違いが最大になります。

したがって、うまくいけば、このスレッドの読者は「IN句は高価であることが知られている」とはもう言わないでしょう:-)

よろしく、
ロブ。

于 2013-03-03T09:06:19.330 に答える
3

この質問は時期尚早の最適化の良い例であり、なぜそれを避けるべきなのかと思います。

テーブルからいくつかのIDの行を取得しようとしています。使用する明らかなクエリは、最も簡単な方法で要件を満たすものである必要があります。非常に正当な理由がない限り、私は常に以下の使用を検討します。

Select * from Table where id in ( 1, 2, 3, 4 );

これにより、後の開発者は何が起こっているのか、そしてその理由が明らかになります。また、データベースに最適化のタスクを任せて処理します。これがデータベースの目的です。

このコードを書いた後、パフォーマンスの問題があることに気付いた場合は、最適化を検討するときです。

あらゆる種類のコードの問題については、通常、最も単純な解決策が最適です。

私はここで少し話題から外れていて、JDBCの知識はあまりありませんが、Oracleの知識はたくさんあります。

于 2013-03-02T22:44:59.423 に答える
3

私はあなたがPreparedStatmentを使用していると仮定します

select * from TABLE where ID=?;

Oracleでは、PreparedStatementを使用すると、OracleはSQLの実行プランの生成をキャッシュできます。したがって、1、2、または1000のIDを渡すと、同じキャッシュされたOracleプランが使用されます。

オラクルは扱います

select * from TABLE where ID in (1, 2, 3);

select * from TABLE where ID in (4, 8, 15, 16, 23, 42);

2つの異なるクエリとして、両方に対して異なる実行プランを生成します。したがって、Oracleの観点からはタイプ1が推奨されます。

実際には、IDにインデックスを付けると、2つのスタイルの重要な違いに気付くことはありません。

いつものようにパフォーマンスチューニングでは、「推測しないで、テストしてください」。YourKitまたはSystem.currentTimeMillis()を使用して、実際の数値を確認します。また、パフォーマンスの向上を無視できるようにするために、コードの明確さを犠牲にしないでください。

于 2013-03-02T18:04:26.187 に答える
0

あなたはオプション3を持っているかもしれません...

私の質問は、どのようにしてそれらのID値を取得したのですか?

一意の識別子のセットを使用してテーブルをクエリする必要があるパターン、奇妙なパターンを見つけました。

(a)取得したい行のまったく同じセットを識別する他の列に述語がある可能性があります。

于 2013-03-03T09:52:59.617 に答える