質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Oracle

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

6回答

15635閲覧

テーブルAに存在していてテーブルBにないデータを高速に抽出したい

koji2017

総合スコア30

Oracle

Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2017/04/23 03:57

編集2017/04/23 05:12

###前提・実現したいこと
テーブルAに存在していてテーブルBにないデータを高速に抽出したい。
テーブルAとBはいずれも100万件以上のデータを持つ別々のテーブル。

###発生している問題・エラーメッセージ

処理に10分以上かかってしまう。

###該当のソースコード

SQL

1select * 2from tableA, tableB 3where tableA.key1 = tableB.key1(+) 4 and tableA.key2 = tableB.key2(+) 5 and tableB.key1 is null

###試したこと
「not exist」を使用する方法も試しましたが遅かったです。

###補足情報(言語/FW/ツール等のバージョンなど)
特になし。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SVC34

2017/04/23 04:19

表と索引のDDLを追記してください
koji2017

2017/04/23 05:06

現在出先でDDLが手元にないです。申し訳ありません。
SVC34

2017/04/23 05:12

目標とする応答時間はどれくらいでしょうか。10分で遅いということはオンライン処理?
koji2017

2017/04/23 05:20

日次のバッチ処理です。今後データが増えても(200万件ずつくらい)10分以下にしたいです。
Zuishin

2017/04/23 05:25

質問の SQL で正しい答えが得られますか? どちらの key1 も null ではないですか?
koji2017

2017/04/23 06:01

SQLを外部結合に修正しました。申し訳ありません。
guest

回答6

0

100万件オーダーのテーブル同士の差分を求めるという要件で10分超を10分以下に抑えるチューニングというのは、改善の余地が小さく労力に対する見返りが少ないと思われます。しかもバッチ処理であればなおさらです。バッチライン上に他にチューニングの余地がないか分析した方が生産的と思いますが、何か事情があるのでしょうか。

おそらく質問者さんが示されているSQLで既に、このようなケースで最も高速と想定されるHASH結合をオプティマイザは選択しているはずです(統計情報がきちんと採られていれば)。実行計画を確認してみてください。なお、ハッシュ結合の場合は結合キーに索引は不要です。

ただし、PGA上のHASHテーブルが溢れてしまうと一時表領域を使用するようになるのでパフォーマンスが低下します。実行計画のTempSpc項目を確認し、一時表領域が使用されていればPGAの拡張を検討してください。

ハッシュ結合

--追記--
key1,key2に索引を追加しても、今のSQLでは結局HASH結合が選択され索引は使用されないと思われます。表の大部分にアクセスするのであれば、1行ずつ索引を見るのはむしろ効率が良くないためです。

索引を追加して性能が改善する可能性があるのは、以下のようにnot exitsと相関複照会を用いたSQLに変更した場合です。こちらであればtableBの表アクセスが不要になるため、性能が向上するかもしれません。ただし、今度は索引へのアクセスが新たにコストとして追加されるため、実測して比較する必要があります。

sql

1select * 2from tableA tA 3where not exists ( 4 select tB.key1 5 from tableB tB 6 where 7 tA.key1 = tB.key1 8 and tA.key2 = tB.key2 9)

投稿2017/04/23 06:12

編集2017/04/23 12:31
SVC34

総合スコア1149

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

出先で詳細情報が出せないため一旦終了します。
申し訳ありません。

投稿2017/04/23 11:04

koji2017

総合スコア30

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

SQLのJOIN文を視覚的に理解する

これを当てはめると

select * from tableA left outer join tableB on tableA.key2 = tableB.key2 where tableB.key1 is null

こうなるのではないでしょうか。
SQL だけではこれで精いっぱいで、高速化にはインデックスが必須だと思います。
逆に言えば、インデックスを張りさえすれば、劇的に高速化すると思います。

投稿2017/04/23 06:38

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SVC34

2017/04/23 07:19

結合条件key1が不足しています。またそれを加えても質問者さんのSQLと同じSQLになります。Oracleでは独自構文として(+)をつけることで外部結合にすることが出来ます。
Zuishin

2017/04/23 11:14 編集

key1 に関してはわざと外しました。私が間違っているのかもしれませんが、よくわかりません。tableA.key1 = tableB.key1 = null で正しく出ますか?
SVC34

2017/04/23 11:43 編集

テーブルAを基準とした左外部結合のため、結合された結果行のうちテーブルBからのカラムが全てNULLになっているものがあれば、その行の左側のテーブルAの部分が「テーブルAに存在していてテーブルBにないデータ」となります。and tableB.key1 is null は結合条件ではなく、結合した結果行に対して評価されます。 図でイメージするOracle DatabaseのSQL全集 第1回 さまざまな結合 http://www.oracle.com/technetwork/jp/articles/otnj-sql-image1-308625-ja.html#p01c
Zuishin

2017/04/23 11:59

おっしゃる通り私が間違えていました。
guest

0

定期不定期に何度も実行する必要があるってことですかね

単発ならkey1、key2をテーブル別にテキストファイルに出力したものをlinuxのcommコマンドとかで比較すれば速そうですが

投稿2017/04/23 04:32

takaboo

総合スコア195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

koji2017

2017/04/23 05:07

お返事ありがとうございます。 日次のバッチです。
guest

0

Oracle はよく知らないのですが、このクエリを実行して時間がかかっとしても期待する結果は返ってきますか?


それはさておき、インデックスを使って外部結合させると高速に抽出ができると思います。

まず tableA および tableB にインデックスを張ります(すでに張ってあるなら作業不要)。

sql

1ALTER TABLE tableA ADD KEY `keys` (`key1`,`key2`); 2ALTER TABLE tableB ADD KEY `keys` (`key1`,`key2`);

で実際のクエリは次のようになります。

sql

1SELECT * FROM tableA 2LEFT OUTER JOIN tableB ON 3tableA.key1=tableB.key1 AND 4tableA.key2=tableB.key2 5WHERE tableB.key1 IS NULL;

MySQL で試しているので、もし方言があったらごめんなさい。

投稿2017/04/23 04:21

miyahan

総合スコア3095

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

koji2017

2017/04/23 05:17

SQLが外部結合になっていなかったので修正しました。 申し訳ありません。 インデックスを追加するのは難しいです。 できればSQLの変更で対応したいです。
miyahan

2017/04/23 05:25

インデックスが使えないとなると難しいですね。 そもそも tableA と tableB の主キーは何でしょうか? また、key1, key2 を含むインデックス・ユニーク制約・外部キー制約等があれば併せて教えてください。
guest

0

SQLに詳しくはありませんが、学生時に習った大雑把な記憶です。

「条件判定の順番として、大きく絞り込めるものを先にすべき。特に、テーブルが膨らむ(例えば総組み合わせの計算をするような)場合は絞り込みをしてからでないと時間とメモリ量が大変になる。

といったことがあったと思います。ご参考までに。

投稿2017/04/23 04:13

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問