web-dev-qa-db-ja.com

IN句が遅すぎる

私は約1時間探していましたが、何も見つかりませんでした。

私はこの問題を抱えています:

このクエリを実行すると:

select order_id
from or_order@smartflex
where order_id in ( select distinct numeroot from oym_planmantenimiento )

時間がかかりすぎて、約1時間の話です!!!

ただし、最初にサブクエリを実行すると、結果がExcelにエクスポートされ(常に100または400の結果のようになります)、静的な値を渡すと、クエリは1秒しかかかりません。

select order_id
from or_order@smartflex
where order_id in ( 1230, 1231, 1232, 1233, ..., 1239 )

サブクエリのようなものを1回だけ実行し、値を渡してから、他のクエリの実行を開始する必要があります。

私に何ができる ?

ありがとう

ロベルトE.

新情報:

テーブルor_orderには78697214とカウントがあります。これは毎秒成長します。テーブルoym_planmantenimientoには最大で10000のレコードがありますが、一意は300〜600程度です。この場合、それは358でした。これは、頻度で変化しますが、毎秒ではなく毎日のようです。したがって、私にとって、クエリの最初の静的な値は十分に正確です。

最初に:

 Plan Hash Value  : 240660835 

----------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name                        | Rows     | Bytes      | Cost  | Time     |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |                             |      702 |      10530 | 96811 | 00:19:22 |
| * 1 |   HASH JOIN RIGHT SEMI  |                             |      702 |      10530 | 96811 | 00:19:22 |
| * 2 |    INDEX FAST FULL SCAN | OYM_PLANMANTENIMIENTO_IDX03 |      832 |       1664 |     6 | 00:00:01 |
|   3 |    REMOTE               | OR_ORDER                    | 78399636 | 1019195268 | 96367 | 00:19:17 |
----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("ORDER_ID"="NUMEROOT")
* 2 - filter("NUMEROOT" IS NOT NULL)

2番目の場合:

 Plan Hash Value  : 

--------------------------------------------------------------------------------
| Id  | Operation               | Name        | Rows | Bytes | Cost | Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT REMOTE |             |  358 |  2148 |  361 | 00:00:01 |
|   1 |   INLIST ITERATOR       |             |      |       |      |          |
| * 2 |    INDEX UNIQUE SCAN    | PK_OR_ORDER |  358 |  2148 |  361 | 00:00:01 |
--------------------------------------------------------------------------------

OYM_PLANMANTENIMIENTOにはインデックスタイプがあります。列numerootに対して通常です。 OR_ORDERにはインデックスタイプがあります。order_idに対して一意です。

1
user3126458

EXISTSを使用

通常、これは EXISTS で解決します

SELECT order_id
FROM or_order@smartflex AS outer
WHERE EXISTS (
  SELECT 1
  FROM oym_planmantenimiento
  WHERE numroot = outer.order_id
);
2
Evan Carroll

「明確」を失う。

すべてtoo多くの場合、[dire]パフォーマンスを犠牲にして、貧弱なデータ構造のバンドエイドとして使用される個別の句を確認します。

明確に重複を削除するなので、常に覚えておいてください...

select distinct a, b, c 
from ... 

...と同じくらい高価になる可能性があります...

select a, b, c
from ... 
group by a, b, c
order by a, b, c 

データベースは、「in」句を満たすために個別の値を必要とせず、1つだけを使用するように強制することは、実行する必要がある作業を増やすのに役立ちますandは、特定の順序で作業を実行することを強制します。ボトルネック、誰か?

もちろん、最善の解決策は結合を使用することです...

select order_id
from or_order@smartflex t1 
inner join oym_planmantenimiento t2 
on t1.order_id = t2.numeroot

...しかし、ここではデータベースリンクを使用しているため、不可能である可能性があります。

0
Phill W.

いくつかのステップでそれを行うことができますか?

CREATE GLOBAL TEMPORARY TABLE my_temp_table 
( numeroot ... )
ON COMMIT DELETE ROWS;

insert into my_temp_table (numeroot) 
select distinct numeroot from oym_planmantenimiento;

SELECT sf.order_id
FROM or_order@smartflex sf
JOIN my_temp_table x
    ON sf.order_id=x.numeroot;

DROP ...;
commit;

もう1つの試みは、非決定的関数を追加してoym_planmantenimientoを具体化することです。私はOracleを知らないので、これはまったく機能しない可能性があります。

WITH y AS ( SELECT numeroot, Rand() as rnd 
            FROM oym_planmantenimiento )
   , x AS ( SELECT distinct numeroot FROM y )
SELECT sf.order_id
FROM or_order@smartflex sf
JOIN x 
    ON sf.order_id=x.numeroot
;
0
Lennart

サブクエリを結合に移動すると、通常は高速になります。ただし、テーブルのクエリには常に、少なくともインデックスと、場合によってはテーブルをスキャンする必要があるため、数値を指定するよりもコストがかかります。両方のテーブルのorder_idにインデックスがありますか?そうでない場合は、追加する必要があります。

SELECT sf.order_id
FROM or_order@smartflex sf
    INNER JOIN (select distinct numeroot from oym_planmantenimiento) x 
        ON sf.order_id=x.numeroot
0
indiri

代わりにこれを試すことができます:

  WITH x 
    AS ( SELECT DISTINCT numeroot 
           FROM oym_planmantenimiento )
SELECT sf.order_id
  FROM or_order@smartflex sf
 INNER JOIN x 
    ON sf.order_id=x.numeroot
  ORDER BY 1;

これにより、本質的に、個別の値の一時テーブルが作成されます。

0
Gandolf989