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

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

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

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

SQL

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

Q&A

解決済

2回答

1598閲覧

インデックスが効くようにしたい SQLが組めずに困っています。

maxLightning

総合スコア13

Oracle

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

SQL

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

0グッド

0クリップ

投稿2018/11/19 15:17

編集2018/11/19 23:29

初心者です。
記載されているSQL(データベース)のFULLSCANをindexを効かせたいです。
使用しているのは SQL Developerです。

主キー
a.カラムA、a.カラムC、
b.カラムA、b.カラムC

index
a.カラムA、a.カラムC、
b.カラムA、b.カラムC

テーブルa
a b c(START) d(END)
0001 aa 17-08-01 17-08-31
0002 ab 18-09-01 18-09-30
0003 ac 18-04-01 18-09-30
0004 ad 17-03-01 18-04-30
0005 ae 18-03-01 99-12-31
: : : :
9999 ad 17-08-31 17-10-31

テーブルb
a b c(START) d(END)
aa 1組 20140801 20160630
aa 2組 20160701 20180930
ab 3組 20180201 20180930
ac 4組 20170101 20180430
ac 5組 20180501 99991231
ad 6組 20180201 99991231
ae 7組 20180201 99991231

ーもとめている実行結果ー
2018年9月の対象者を実行結果として表示させたいです

テーブルa
a b c d
0002 ab 18-09-01 18-09-30
0003 ac 18-04-01 18-09-30
0005 ae 18-03-01 99-12-31

テーブルb
a b c d
ab 3組 20180201 20180930
ac 5組 20180501 99991231
ae 6組 20180201 99991231

該当のソースコード

SQL SELECT a.カラムA(varchar2型) a.カラムB(varchar2型) a.カラムC(date型) a.カラムD(date型) b.カラムA(varchar2型) b.カラムB(varchar2型) b.カラムC(varchar2型) b.カラムD(varchar2型) FROM テーブルa,テーブルb WHERE a.カラムB=b.カラムA AND (a.カラムA、a.カラムC、b.カラムA、b.カラムC) IN (SELECT a.カラムA、 MAX(a.カラムC)、 b.カラムA、 MAX(b.カラムC) FROM テーブルa、テーブルb WHERE a.カラムB=b.カラムA AND a.カラムC<= TO_DATE('20180930','YYYYMMDD') AND a.カラムD >=TO_DATE('20180901','YYYYMMDD') AND b.カラムC<= '20180930' AND b.カラムD >='20180901' GROUP BY a.カラムA、b.カラムA )

考えられる原因
(1)IN句が使っているためインデックスが効かず、フルスキャンされてしまう。

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

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

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

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

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

m.ts10806

2018/11/19 22:10

表もマークダウンで組めるのでそちらをご利用ください
guest

回答2

0

テーブル定義やインデックス定義はCREATE TABLE, CREATE INDEX を、統計情報を取得 し、実行計画対応しているMarkdownの機能 の[コードを入力]を使ってください。

saziさんのコードを一部修正。

SQL

1 AND b.カラムC<='20180930' 2 AND b.カラムD>='20180901'

SQL

1 AND b.カラムC<=TO_DATE('20180930','YYYYMMDD') 2 AND b.カラムD>=TO_DATE('20180901','YYYYMMDD')

full scan になり易いので暗黙の型変換に頼ってはなりません。

投稿2018/11/19 22:16

Orlofsky

総合スコア16415

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

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

sazi

2018/11/20 00:23

テーブルAでは型変換行っていますし、テーブルBのサンプルも日付型ではないようですから、特に変換はかけていません。
Orlofsky

2018/11/20 00:29

あら、date型じゃないのね。 このシステムの開発はいばらの道ですなぁ。
maxLightning

2018/11/20 03:32

Orlofskyさん、回答ありがとうございます。 ありがとうございます いばらのみちを突き進みます
Orlofsky

2018/12/06 07:41

変に設計してしまったテーブルを直す、って選択肢もあります。
guest

0

ベストアンサー

見辛いので、整形しました。

SQL

1SELECT * 2FROM テーブルa,テーブルb 3WHERE a.カラムB=b.カラムB 4 AND (a.カラムA, a.カラムC, b.カラムA, b.カラムC) IN ( 5 SELECT a.カラムA, MAX(a.カラムC), b.カラムA, MAX(b.カラムC) 6 FROM テーブルa, テーブルb 7 WHERE a.カラムB=b.カラムB 8 AND a.カラムC<=TO_DATE('20180930','YYYYMMDD') 9 AND a.カラムD>=TO_DATE('20180901','YYYYMMDD') 10 AND b.カラムC<='20180930' 11 AND b.カラムD>='20180901' 12 GROUP BY a.カラムA, b.カラムA 13 )

主キー
a.カラムA, a.カラムC、
b.カラムA, b.カラムC

index
a.カラムA, a.カラムC、
b.カラムA, b.カラムC

同じ内容のインデックスなので、無駄です。

現状でインデックスが効かないなら、インデックスを以下のようにしてみる。

index

--サブクエリー用
a.カラムC, a.カラムD, a.カラムB, a.カラムA
b.カラムC, b.カラムD, b.カラムB, b.カラムA
--メイン用
a.カラムB, a.カラムA, a.カラムC
b.カラムB, b.カラムA, b.カラムC
または
a.カラムA, a.カラムC, a.カラムB
b.カラムA, b.カラムC, b.カラムB

where条件やgroup by 項目などがインデックスに含まれるようにする事と、
範囲の大きいものから小さいもの順にインデックス項目が並ぶようにすると良いと思います。

インデックスの並びを変えたりしながら、実行計画を見つつチューニングして下さい。

追記

SQLを別な組み立てにすると、以下の様になるかと思います。

SQL

1select * 2from テーブルa as a inner join テーブルb b 3 on a.カラムB=b.カラムB 4where a.カラムC = ( 5 select max(カラムC) from テーブルa 6 where カラムA=a.カラムA 7 and カラムC<=TO_DATE('20180930','YYYYMMDD') 8 and カラムD>=TO_DATE('20180901','YYYYMMDD') 9 ) 10 and b.カラムC = ( 11 select max(カラムC) from テーブルb 12 where カラムA=b.カラムA 13 and カラムC<='20180930' 14 and カラムD>='20180901' 15 )

または、

SQL

1select * 2from テーブルa as a inner join テーブルb b 3 on a.カラムB=b.カラムB 4where (a.カラムA, a.カラムC) in ( 5 select カラムA, max(カラムC) from テーブルa 6 where カラムC<=TO_DATE('20180930','YYYYMMDD') 7 and カラムD>=TO_DATE('20180901','YYYYMMDD') 8 group by カラムA 9 ) 10 and (b.カラムA, b.カラムC = ( 11 select カラムA, max(カラムC) from テーブルb 12 where カラムA=b.カラムA 13 and カラムC<='20180930' 14 and カラムD>='20180901' 15 group by カラムA 16 )

こっちだと、

--サブクエリー用
a.カラムA, a.カラムC, a.カラムD
b.カラムA, b.カラムC, b.カラムD
--メイン用
a.カラムB, a.カラムA, a.カラムC
b.カラムB, b.カラムA, b.カラムC

もう1パターン。(これが一番素直な絞り込み[高速?]な気がします)

SQL

1select * 2from テーブルa as a inner join テーブルb b 3 on a.カラムB=b.カラムB 4where a.カラムC<=TO_DATE('20180930','YYYYMMDD') 5 and a.カラムD>=TO_DATE('20180901','YYYYMMDD') 6 and a.カラムC=( 7 select max(カラムC) from テーブルa where カラムA=a.カラムA 8 ) 9 and b.カラムC<='20180930' 10 and b.カラムD>='20180901' 11 and b.カラムC=( 12 select max(カラムC) from テーブルb where カラムA=b.カラムA 13 )

投稿2018/11/19 15:44

編集2018/11/20 01:01
sazi

総合スコア25173

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

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

maxLightning

2018/11/19 23:01

お忙しい中、早急な回答ありがとうございます。 回答のとおり確認してみます。
maxLightning

2018/11/20 03:36

回答ありがとうございます。 お忙しい中、SQL文を組み立ててくれてありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問